Will LoaderManager.restartLoader() always result in a call to onCreateLoader()?

Maarten picture Maarten · Jan 21, 2014 · Viewed 14.7k times · Source

LoaderManager has this method restartLoader():

public abstract Loader<D> restartLoader (int id, Bundle args, LoaderCallbacks<D> callback)

Starts a new or restarts an existing Loader in this manager, registers the callbacks to it, and (if the activity/fragment is currently started) starts loading it. If a loader with the same id has previously been started it will automatically be destroyed when the new loader completes its work. The callback will be delivered before the old loader is destroyed.

Based on the dev guide, I get the idea that indeed, a call to onCreateLoader will always result from restartLoader():

Restarting a Loader

...

To discard your old data, you use restartLoader(). For example, this implementation of SearchView.OnQueryTextListener restarts the loader when the user's query changes. The loader needs to be restarted so that it can use the revised search filter to do a new query:

public boolean onQueryTextChanged(String newText) {
    // Called when the action bar search text has changed.  Update
    // the search filter, and restart the loader to do a new query
    // with this filter.
    mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
    getLoaderManager().restartLoader(0, null, this);
    return true;
}

public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    // NOTE: The Loader is instantiated with the user's query

    Uri baseUri;       
    if (mCurFilter != null) {
        baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
                  Uri.encode(mCurFilter));
    } else {
        baseUri = Contacts.CONTENT_URI;
    }

    // Now create and return a CursorLoader that will take care of
    // creating a Cursor for the data being displayed.
    String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND ("
            + Contacts.HAS_PHONE_NUMBER + "=1) AND ("
            + Contacts.DISPLAY_NAME + " != '' ))";
    return new CursorLoader(getActivity(), baseUri,
            CONTACTS_SUMMARY_PROJECTION, select, null,
            Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
}

In the example, onCreateLoader is the only place where information about the user's query is passed to the Loader (on instantiation). However the docs throw me off, by saying 'Starts a new or restarts an existing Loader'.

Answer

NigelK picture NigelK · Jan 21, 2014

The simple answer to your question is yes, a call to restartLoader() will call onCreateLoader() again.

You can start more than one loader in parallel (say you have two SimpleCursorAdapters to fill), e.g.:

getLoaderManager().initLoader(0, null, this);  //id = 0
getLoaderManager().initLoader(1, null, this);  //id = 1

onCreateLoader is then called by the Loader Manager for each id (the loader that is returned is then built asynchronously by the Loader Manager):

public Loader<Cursor> onCreateLoader(int id, Bundle args)
{
    if (id == 0)
        //return a Loader<Cursor> for id 0
    else if (id == 1)
        //return a Loader<Cursor> for id 1
}

The Loader Manager passes the resulting loader to onLoadFinished:

public void onLoadFinished(Loader<Cursor> loader, Cursor cursor)
{
    if (loader.getId() == 0)
        //cursor was returned from onCreateLoader for id 0
        //perhaps do swapCursor(cursor) on an adapter using this loader
    else if (loader.getId() == 1)
        //cursor was returned from onCreateLoader for id 1
        //perhaps do swapCursor(cursor) on an adapter using this loader
}

When you subsequently call restart loader:

getLoaderManager().restartLoader(0, null, this);  //id = 0

...onLoaderReset is first called:

public void onLoaderReset(Loader<Cursor> loader)
{
    if (loader.getId() == 0)
        //perhaps do swapCursor(null) on an adapter using this loader
    else if (loader.getId() == 1)
        //perhaps do swapCursor(null) on an adapter using this loader
}

...followed by a new call to onCreateLoader. So in that respect, onCreateLoader is used both to start a brand new loader and when an existing loader is reset.