Why cursorLoader didn't notify changes in source data?

ilcaduceo picture ilcaduceo · Dec 29, 2011 · Viewed 8.1k times · Source

I have a simple contentProvider, a layout with a ListView and a button for adding Items in content Provider and a CursorLoader. The http://developer.android.com/reference/android/app/LoaderManager.LoaderCallbacks.html#onLoadFinished(android.content.Loader, D) reference states that

The Loader will monitor for changes to the data, and report them to you through new calls here. You should not monitor the data yourself. For example, if the data is a Cursor and you place it in a CursorAdapter, use the CursorAdapter(android.content.Context, android.database.Cursor, int) constructor without passing in either FLAG_AUTO_REQUERY or FLAG_REGISTER_CONTENT_OBSERVER (that is, use 0 for the flags argument). This prevents the CursorAdapter from doing its own observing of the Cursor, which is not needed since when a change happens you will get a new Cursor throw another call here.

But the Log.info line in the onLoadFinished method was not executed and listView didn't refreshed. Here is my (simple) code:

public class HomeActivity extends FragmentActivity implements LoaderManager.LoaderCallbacks<Cursor>{
static final String TAG = "HomeActivity";
SimpleCursorAdapter adapter;
ListView listAnnunciVicini;

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.home);

    listAnnunciVicini = (ListView) findViewById(R.id.lista_annunci_vicini);

    adapter = new SimpleCursorAdapter(this, R.layout.list_item, null, 
            new String[] {
                    ContentDescriptor.Annunci.Cols.ID, 
                    ContentDescriptor.Annunci.Cols.TITOLO, 
                    ContentDescriptor.Annunci.Cols.DESCRIZIONE 
            }, new int[] { 
                    R.id.list_annunci_item_id_annuncio, 
                    R.id.list_annunci_item_titolo_annuncio,
                    R.id.list_annunci_item_descrizione_annuncio
            }, 0);
    listAnnunciVicini.setAdapter(adapter);

    // Prepare the loader. Either re-connect with an existing one,
    // or start a new one.
    getSupportLoaderManager().initLoader(0, null, this).forceLoad();
}

public void addRandomItem(View sender) {
    ContentValues dataToAdd = new ContentValues();
    dataToAdd.put(ContentDescriptor.Annunci.Cols.TITOLO, "Titolo");
    dataToAdd.put(ContentDescriptor.Annunci.Cols.DESCRIZIONE, "Lorem ipsum dolor sit amet.");
    this.getContentResolver().insert(ContentDescriptor.Annunci.CONTENT_URI, dataToAdd);
}

@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    // creating a Cursor for the data being displayed.
    String[] proiezione = new String[] {ContentDescriptor.Annunci.Cols.ID, ContentDescriptor.Annunci.Cols.TITOLO, ContentDescriptor.Annunci.Cols.DESCRIZIONE };

    CursorLoader cl = new CursorLoader(this, ContentDescriptor.Annunci.CONTENT_URI, proiezione, null, null, null);
    return cl;
}

public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    // Swap the new cursor in.  (The framework will take care of closing the
    // old cursor once we return.)
    adapter.swapCursor(data);
    Log.i(TAG, "I dati sono stati ricaricati");
}

public void onLoaderReset(Loader<Cursor> loader) {
    // This is called when the last Cursor provided to onLoadFinished()
    // above is about to be closed.  We need to make sure we are no
    // longer using it.
    adapter.swapCursor(null);
}
}

Any suggestion?

Answer

ernazm picture ernazm · Dec 29, 2011

AFAIK, you need to implement notification yourself in ContentProvider. For this, add something like getContext().getContentResolver().notifyChange(uri, null); to insert,update and delete method of ContentProvider and invoke.setNotificationUri(getContext().getContentResolver(), uri) on your Cursor in queryas described in official documentation. Here you can find the whole picture.

Note: You should not close the cursor (cursor.close()) in order to get notifications about the changes.