Android Simplecursoradapter Doesn't Update When Database Changes

Android SimpleCursorAdapter doesn't update when database changes

Call requery() on the Cursor when you change data in the database that you want reflected in that Cursor (or things the Cursor populates, like a ListView via a CursorAdapter).

A Cursor is akin to an ODBC client-side cursor -- it holds all of the data represented by the query result. Hence, just because you change the data in the database, the Cursor will not know about those changes unless you refresh it via requery().


UPDATE: This whole question and set of answers should be deleted due to old age, but that's apparently impossible. Anyone seeking Android answers should bear in mind that the Android is a swiftly-moving target, and answers from 2009 are typically worse than are newer answers.

The current solution is to obtain a fresh Cursor and use either changeCursor() or swapCursor() on the CursorAdapter to affect a data change.

Android ListView update with SimpleCursorAdapter

Have you seen this, tried the swap cursor method, or tried just simply calling setAdapter() again?

I had a similar issue where I could not get my list to update, and what I did was just create a refreshListView() method. Now you can call this initially from your onCreate(), AND anytime a user adds something to the DB. All it does is re-bind the listview to a cursor. With all the deprecating methods (requery()), and issues with notifyDataSetChanged(), I decided this was the easiest way.

Listview not updating after database update and adapter.notifyDataSetChanged();

Using adapter.swapCursor(cursor) is correct so you're almost there in answering your own question.

Your first piece of code doesn't work because when you call fillData() after your database update, you simply call adapter.notifyDataSetChanged() and the dataset hasn't actually changed because the cursor is the same. A cursor is a reference to rows from your database and updating the underlying database doesn't refresh the cursor. Your second piece of code does refresh the cursor and swaps the new one in to the adapter (which also triggers an update to the view it is bound to).

The more common way to code this is:

Add this interface to your activity:

public class MyActivity extends Activity implementsLoaderManager.LoaderCallbacks<Cursor>

In onCreate, set up the adapter (note that the cursor is null at this point):

String[] from = new String[] { TodoTable.COLUMN_SUMMARY, TodoTable.COLUMN_ID};
int[] to = new int[] { R.id.label };
adapter = new SimpleCursorAdapter(this, R.layout.todo_row, null, from, to, 0); //Note that the cursor is null
lw.setAdapter(adapter);

Initiate the loader:

getLoaderManager().initLoader(0, null, this);

This calls onCreateLoader in a background thread (so if your query is long running it won't block the UI thread). When it finishes, onLoadFinished is called on the UI thread where you can swap in the new cursor.

After you do a delete or update, restart the loader:

getLoaderManager().restartLoader(0, null, this);

This calls onLoaderReset which removes the existing cursor from the adapter and then calls onCreateLoader again to swap in a new one.

Finally add these methods:

public Loader<Cursor> onCreateLoader(int id, Bundle args)
{
String[] from = new String[] { TodoTable.COLUMN_SUMMARY, TodoTable.COLUMN_ID};
String where = TodoTable.COLUMN_DELETED + " = ?";

Loader<Cursor> loader = new CursorLoader(this, TodoContentProvider.CONTENT_URI, from, where, new String[] {"0"}, null);
return loader;
}

public void onLoadFinished(Loader<Cursor> loader, Cursor cursor)
{
adapter.swapCursor(cursor);
}

public void onLoaderReset(Loader<Cursor> loader)
{
adapter.swapCursor(null);
}

Listview not updating after DB insert

You should get the cursor again after data changed and then swap it with current cursor and notify change to adapter:

Cursor mpgCur = mpgDB.query(dbMain.TABLE_NAME, PROJECTION, null, null, null, null, null);
vehAdapter.swapCursor(mpgCur);
vehAdapter.notifyDataSetChanged();

There's no need to create the adapter again.

CursorLoader not updating after data change

Did you call setNotificationUri(ContentResolver cr, Uri uri) on the Cursor before returning it in ContentProvider.query()?

And did you call getContext().getContentResolver().notifyChange(uri, null) in the 'insert' method of your ContentProvider?

EDIT:

To get a ContentResolver call getContext().getContentResolver() in your ContentProvider.

ContentLoader not properly refreshing after database changes

I think your

getContext().getContentResolver().notifyChange(uri, null);

may be fine.

I can't see your query function for your DatabaseProvider, but did you remember to set the notificationUri for the cursor you are returning in your query function?

In your query() function of the DatabaseProvider, you should set the notification Uri for the cursor, or else the cursor won't get a notification even if you do a notifyChange():

public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
// blah blah
cursor.setNotificationUri(getContext().getContentResolver(), uri);
}


Related Topics



Leave a reply



Submit