Loaders and onLoaderReset Android

Sandra picture Sandra · Oct 17, 2012 · Viewed 11.1k times · Source

I implemented a Loader in my application for querying data from the database. I listen the changes that happen' by implementing LoaderCallbacks<Cursor> listener. The problem that I have is when using the onLoaderReset(Loader<Cursor> loader) method when my data change and I want to invalidate and free any data associated with the loader. In all the examples, in this method there is the following call:

mAdapter.swapCursor(null);

But the thing is I don't use the data from the cursor in adapter, I use it in some other way in my application.

(directly from the returned cursor in onLoadFinished(Loader<Cursor> loader, Cursor data), for example)

        @Override
        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {

            if (data.moveToFirst()) {
                TOTAL_CARDS = data.getCount();
                mView.createCards(TOTAL_CARDS);
            } else {
                TOTAL_CARDS = 0;
                mView.createCards(TOTAL_CARDS);
            }


        }

What would be the corresponding thing to do here, that is similar with mAdapter.swapCursor. I don't have much experience with loaders, in fact I just started working with them, so if someone has a solution to this, I would appreciate it. Thx!

EDIT: For now, I am passing null to the loader and it works, like this:

@Override
public void onLoaderReset(Loader<Cursor> loader) {
        loader = null;
}

};

But is this the right solution?

Answer

Rafael Winterhalter picture Rafael Winterhalter · May 2, 2013

Doing

@Override
public void onLoaderReset(Loader<Cursor> loader) {
  loader = null;
}

is just as good as doing nothing. In your example code, you are merely nulling your method's local reference to its argument. However, this reference will always be removed after the return of the method call. (You might want to read Is Java "pass-by-reference" or "pass-by-value"? for a further discussion of the topic.)

The onLoaderReset(Loader) method gets called when your loader's callback (usually an Activity or Fragment instance) is asked to release all references to the Cursor which it has gained via onLoadFinished(Loader, Cursor) before. Basically this method asks you to clean up since the Loader will soon close the Cursor it provided to you before. After the cursor was closed, you will not longer be able to retrieve data by it. If the cursor would however still be in use (typically by a CursorAdapter as you mentioned) after it was closed, this would cause an exception to be thrown.

Similarly, onLoadFinished(Loader, Cursor) has an implicit contract asking that after the method returns any formerly provided Cursor objects must not longer be in use. Instead, you have to replace these references by the new cursor which is provided as a method argument. In contrast, onLoaderReset(Loader) asks you to fulfill the same contract, but without providing a replacement, i.e. you should remove all references to a formerly retrieved Cursor.

In your example, you do not let your Cursor escape the method scope but instead you are reading the data right away. Therefore, it is not necessary to remove any references to a Cursor object which was provided via onLoadFinished(Loader, Cursor) since there are none. An empty implementation of onLoaderReset(Loader) to fulfill the interface contract will therefore do the job for you.