Tuesday, August 13, 2013

CursorLoader - asynchronous loader of data

Today I want to show how to work with CursorLoader for asynchronously loading data from a database.
While doing my "pet" project I noticed that now I have a lot of data and its loading takes some time especially for the first start of app when db is also initialized. I do not want to get "ANR" in my app, so I started looking for the solution.

So I had an activity - child of ListActivity on which I show result. Code looks like as shown below:

public class MainActivity extends ListActivity {

  private final Uri VOCABULARY_URI = Uri.EMPTY; //Only for example you need added real Uri to your data
    
  private final String[] COUNM_NAMES = new String[] { "native_word", "translation_word" };

  private final int[] VIEW_IDS = new int[] { R.id.native_word, R.id.translated_word };
  private final String[] PROJECTION = new String[] { "_id", "native_word", "translation_word" };

  @Override
  public void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
        
    Cursor cursor = getContentResolver().query(VOCABULARY_URI, PROJECTION, null, null, null); //The most expensive operation
        
    SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.two_item_in_line, cursor, COUNM_NAMES, VIEW_IDS);
    setListAdapter(adapter);
  }
}

CursorLoader was added in API level 11, but if your app supported a lower api level it is not a problem  as you could use Support Library. This library provides backward-compatible features like Fragment which were added in last revisions.
Now my activity is needed to implement LoaderManager.LoaderCallbacks with following methods:

onCreateLoader(int id, Bundle args) - instantiate and return a new Loader for given id
onLoadFinished(Loader<Cursor> loader, Cursor cursor) - called when a previously created loader has finished its load
onLoaderReset(Loader<Cursor>) - called when a previously created loader is being reset, and thus its data unavailable.

And following is my realization:
  @Override
  public Loader<Cursor>onCreateLoader(final int loaderId, final Bundle bundle) {
    switch (loaderId) {
    case VOCABLUARY_LOADER_ID:
      return new CursorLoader(getActivity(), VOCABULARY_URI, PROJECTION, null, null, null);
    default:
      return null;
    }
  }

  @Override
  public void onLoadFinished(final Loader<Cursor> cursorLoader, final Cursor cursor) {
    adapter.changeCursor(cursor);
  }

  @Override
  public void onLoaderReset(final Loader<Cursor> cursorLoader) {
    adapter.changeCursor(null);
  }

That`s all, nice work :-)

No comments:

Post a Comment