Reputation: 39
SimpleCursorAdaptor is deprecated. I found out it's not going to be ideal for me because it uses the UI thread and I will be displaying a few hundred records. I want to use something that uses a background thread. After some research, I came across CursorLoader. I have been looking at tutorials but I'm finding it really tricky to implement. If there is a better alternative to CursorLoader, let me know. Please could someone help me out. The code I have so far. is:
public void getListFromDb(){
Cursor res = myDb.ViewAll();
startManagingCursor(res);
//Map cursor from db to viewFields
String[] fromFieldNames = new String[]{DatabaseHelper.COL_2, DatabaseHelper.COL_3, DatabaseHelper.COL_4, DatabaseHelper.COL_5};
int[] toViewIDS = new int[]{R.id.viewName, R.id.viewAddress, R.id.viewPostcode, R.id.viewType};
//Create adaptor to map items from DB to UI
SimpleCursorAdapter myCursorAdaptor = new SimpleCursorAdapter(this, R.id.item_layout, res, fromFieldNames, toViewIDS);
// Set adaptor for listView
ListView myList = (ListView) findViewById(R.id.listViewLocations);
myList.setAdapter(myCursorAdaptor);
}
Upvotes: 1
Views: 109
Reputation: 1858
Actually only one of the SimpleCursorAdapter constructors is depricated, not the entire class. You can still use it, but you must use the "standard" constructor which requires a value for the "flags" parameter.
public void getListFromDb(){
Cursor res = myDb.ViewAll();
startManagingCursor(res);
//Map cursor from db to viewFields
String[] fromFieldNames = new String[]{DatabaseHelper.COL_2, DatabaseHelper.COL_3, DatabaseHelper.COL_4, DatabaseHelper.COL_5};
int[] toViewIDS = new int[]{R.id.viewName, R.id.viewAddress, R.id.viewPostcode, R.id.viewType};
//Create adaptor to map items from DB to UI
// *** ADD THE FLAGS PARAMETER ***
SimpleCursorAdapter myCursorAdaptor = new SimpleCursorAdapter(this, R.id.item_layout, res, fromFieldNames, toViewIDS, FLAG_AUTO_REQUERY);
// Set adaptor for listView
ListView myList = (ListView) findViewById(R.id.listViewLocations);
myList.setAdapter(myCursorAdaptor);
}
I've added "FLAG_AUTO_REQUERY" to make the change obvious, but I suspect you might want to use the value "0" (no flags) unless your data can change while being displayed.
So after re-reading your question (sorry, my bad; I should really read more carefully :-p ) your real problem is how to load the data on a background thread. There are quite a few ways of doing this, all have good and bad points.
There are two parts to this classic Android problem: 1: Actually loading the data on a background thread and handing the results to the UI thread for display. 2: Surviving activity destruction/resume typically caused by rotation (but can be caused by something as uncontrollable as a phone call being received).
CursorLoaders are clumsy and awkward to implement but do actually solve both problems pretty well..
AsyncTasks will handle background execution and passing the results to the ui thread and work well if you don't care about problem 2, however there is a nasty little issue in android that can result in only one AsyncTask running at a time (not great if you want to do lots of work in parallel).
There are also other frameworks that can be used to do this kind of work like rxJava and otto but they require a considerable effort to become comfortable with initially (although arguably worthwhile).
If you need to worry about rotation and/or interruption of your application I would suggest CursorLoaders might be the easiest initially, but only for simpler applications. If your application is going to be complicated, invest some time in looking at rxJava or Otto.
Hope this helps. P.S. Simple asynctask based example (haven't tested as I dont have all your source/resources, but you get the idea..)
public void getListFromDb(){
//Map cursor from db to viewFields
String[] fromFieldNames = new String[]{DatabaseHelper.COL_2, DatabaseHelper.COL_3, DatabaseHelper.COL_4, DatabaseHelper.COL_5};
int[] toViewIDS = new int[]{R.id.viewName, R.id.viewAddress, R.id.viewPostcode, R.id.viewType};
// Notice I am passing null as the cursor..
SimpleCursorAdapter myCursorAdaptor = new SimpleCursorAdapter(this, R.id.item_layout, null, fromFieldNames, toViewIDS, 0);
// Set adaptor for listView
ListView myList = (ListView) findViewById(R.id.listViewLocations);
myList.setAdapter(myCursorAdaptor);
new AsyncTask<SimpleCursorAdapter, Void, Cursor>() {
private SimpleCursorAdapter mSimpleCursorAdapter;
@Override
protected Cursor doInBackground(SimpleCursorAdapter... params) {
// Save cursorAdapter to use in postExecute
this.mSimpleCursorAdapter = params[0];
// Load cursor on background thread
return myDb.ViewAll();
}
@Override
protected void onPostExecute(Cursor cursor) {
super.onPostExecute(cursor);
// and update the cursor (which is already in the listview)
this.mSimpleCursorAdapter.changeCursor(cursor);
}
}.execute(myCursorAdaptor);
}
The main "trick" to it is that I initially create the simplecursoradapter with a null cursor; this allows me to get the list on the screen with no data. I then start an AsyncTask, passing the cursoradapter to it and get it to load the cursor on a background thread. I then call "changeCursor" on the adapter and it should update the listview with the loaded data. You could also use onPreExecute to show a busy "spinner" and hide the busy "spinner" in onPostExecute.. just to let the user know you are doing something.. Oh, just in case you missed it; onPreExecute and onPostExecute run on the UI thread so can update the UI, doInBackground runs on a background thread..
Upvotes: 1