Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: how to use CursorAdapter?

I have a database, a ListView, and a CustomCursorAdapter that extends CursorAdapter. A menu button adds an item to the database. I want the ListView to update and show this change. Normally it doesn't show this new item until i go to the homescreen and reopen the application.

I did eventually get it to work by calling cursor.requery() or mCustomCursorAdapter.changeCursor(newCursor) whenever I added a new item, but when I set autoRequery to false in the CursorAdapter constructor, it worked just the same. Why does it update correctly when autoRequery is set to false?

Am I using CursorAdapter correctly? What is the standard way of keeping the list updated with the database? And what does autoRequery do?

like image 395
user316146 Avatar asked Aug 23 '10 05:08

user316146


2 Answers

The idiomatic and imho correct way to automatically update Cursors is to call Cursor#setNotificationUri when they are created and before they are handed off to whatever requested them. Then call ContentResolver#notifyChange when anything in that Cursor's Uri's namespace changes.

For example, suppose you were creating a simple mail application and you wanted to update when new mail arrived but also provide various views on the mail. I'd have some basic Uri's defined.

content://org.example/all_mail
content://org.example/labels
content://org.example/messages

Now, say I wanted to get a cursor that gave me all mail and be updated when new mail arrives:

Cursor c;
//code to get data
c.setNotificationUri(getContentResolver(), Uri.parse("content://org.example/all_mail");

Now new mail arrives so I notify:

//Do stuff to store in database
getContentResolver().notifyChange(Uri.parse("content://org.example/all_mail", null);

I should also notify all the Cursors that selected for labels this new message met

for(String label : message.getLabels() {
  getContentResolver().notifyChange(Uri.parse("content://org.example/lables/" + label, null);
}

And also, maybe a cursor is viewing that one specific message so notify them as well:

getContentResolver().notifyChange(Uri.parse("content://org.example/messages/" + message.getMessageId(), null);

The getContentResolver() calls happen where the data is accessed. So if it's in a Service or ContentProvider that is where you setNotificationUri and notifyChange. You should not be doing that from where the data is accessed, e.g., an Activity.

AlarmProvider is a simple ContentProvider that uses this method to update Cursors.

like image 200
Rich Schuler Avatar answered Oct 09 '22 17:10

Rich Schuler


I created next method for ListView updating:

/**
 * Method of refreshing Cursor, Adapter and ListView after database 
 * changing
 */
public void refreshListView() {
    databaseCursor = db.getReadableDatabase().query(
            CurrentTableName, 
            null, 
            null, 
            null, 
            null, 
            null, 
            "title"+SortingOrder);
    databaseListAdapter = new DomainAdapter(this, 
            android.R.layout.simple_list_item_2, 
            databaseCursor, 
            new String[] {"title", "description"}, 
            new int[] { android.R.id.text1, android.R.id.text2 });
    databaseListAdapter.notifyDataSetChanged();
    DomainView.setAdapter(databaseListAdapter);
}

end calls it each time after some changing in database

like image 20
Anton Derevyanko Avatar answered Oct 09 '22 17:10

Anton Derevyanko