Android CursorAdapters, ListViews and Background Threads
This application I was working on has databases with several megabytes of data to sift through. Many of them are simply ListViews that descend through various levels of data in databases until we reach βdocumentsβ that are simply pulled from the database (DB) and displayed on the phone. The problem I'm running into is that some of these actions should be able to search through databases, capturing keystrokes and rerunning the query with "like% blah%" in it. This works reasonably fast, except when the user loads data first and when the user types a keystroke first. I am using ResourceCursorAdapter and I am generating cursor on background thread, but in order to do listAdapter.changeCursor (),I have to use a handler to send it to the main UI thread. This particular call then freezes the UI thread long enough to trigger the awful ANR dialog. I am curious how I can fully load this into a background thread to keep the UI responsive and we don't have ANR dialogs.
Just for full disclosure, I originally returned an ArrayList of custom model objects and used an ArrayAdapter, but (understandably) the client indicated it was poor memory management and I was still unhappy with the performance. I would really like to avoid a solution where I create huge lists of objects and then do listAdapter.notifyDataSetChanged / Invalidated ()
Here is the code in question:
private Runnable filterDrugListRunnable = new Runnable() {
public void run() {
if (filterLock.tryLock() == false) return;
cur = ActivityUtils.getIndexItemCursor(DrugListActivity.this);
if (cur == null || forceRefresh == true) {
cur = docDb.getItemCursor(selectedIndex.getIndexId(), filter);
ActivityUtils.setIndexItemCursor(DrugListActivity.this, cur);
forceRefresh = false;
}
updateHandler.post(new Runnable() {
public void run() {
listAdapter.changeCursor(cur);
}
});
filterLock.unlock();
updateHandler.post(hideProgressRunnable);
updateHandler.post(updateListRunnable);
}
};
source to share
I find it hard to believe that it listAdapter.changeCursor()
would only take long enough to trigger the ANR if you created Cursor
on a background thread. There shouldn't be so much work that needs to happen to redraw multiple lines of the list. I would double check to see what kind of work you do in your Handler is limited as you think. Perhaps consider using AsyncTask, which will make it easier to separate background work ( doInBackground()
) from subsequent processing by UI thread ( onPostExecute()
).
You can try to simply replace the adapter directly by calling again setAdapter()
with a new Cursor
one wrapped in a new adapter.
You can see how AutoCompleteTextView
this script handles as it does filtering on the fly with SpinnerAdapter
. Perhaps some of his methods can be applied in your case.
source to share
Just posted an answer here: Android: Refresh Listview after Thread downloads data from network
Short: AsyncTask's onProgressUpdate method can touch the view: http://developer.android.com/reference/android/os/AsyncTask.html#onProgressUpdate (Progress ...)
source to share