David Doria David Doria - 3 months ago 9
Android Question

AsyncTaskLoader doesn't call onLoadFinished unless I return a new object in loadInBackground

I have a

AsyncTaskLoader<List<String>>
with a member variable
List<String>
mAddresses. In
loadInBackground
, if I create a new object, fill it, and return it;
onLoadFinished
is called as expected, so I can update the adapter which in turn updates the view.

public List<String> loadInBackground()
{
// ListView updates properly only if I do this (strange?)
mAddresses = new ArrayList<String>();

// ... fill mAddresses ...

return mAddresses;
}


However, if I try to use the same variable even when it's value changes
onLoadFinished
does get called:

public List<String> loadInBackground()
{
// ListView does not update with this!
if(mAddresses == null)
{
mAddresses = new ArrayList<String>();
}

// ... fill mAddresses ...

return mAddresses;
}


Can anyone comment on this? Am I supposed to create a new object to return each time like this? Is there any flag I can set that says "the object has changed, so even though it is the same object, make sure all of the updates are performed?

Answer

If the data is already loaded (as it seems in your 'mAddresses' variable which is in the Loader) you need to call forceLoad() to get it to load again:

http://developer.android.com/reference/android/content/Loader.html#forceLoad%28%29



Edit: ...after some investigation... To answer your original question, unhelpfully: 'because it doesn't'!

From the source for LoaderManager:

        // Notify of the new data so the app can switch out the old data before
        // we try to destroy it.
        if (mData != data || !mHaveData) {
            mData = data;
            mHaveData = true;
            if (mStarted) {
                callOnLoadFinished(loader, data);
            }
        }

http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.3_r2.1/android/app/LoaderManager.java#LoaderManagerImpl.LoaderInfo.onLoadComplete%28android.content.Loader%2Cjava.lang.Object%29

RE your problem, I'm assuming that you're continually adding to the List in loadInBackground() rather than clearing and starting again. The cleanest way is to build a new ArrayList each time by passing in the existing List as an argument to the ArrayList() constructor, it will copy the contents.
Or you could override deliverResult(), it's called from the main thread so modifying mAdapter is OK.
Or forget the Loader and just use a much simpler AsyncTask... although that depends on where your data actually comes from.

Comments