First I should mention that I am using the ActionBarSherlock library for backwards compatibility.
I have an activity which adds a ListFragment when it is first started. I have a custom Loader which I implemented and follows the AsnycTaskLoader example very closely. My ListFragment implements the LoaderCallbacks<Cursor> interface. All the appropriate callback methods are called when the fragment is added (onCreateLoader() , onLoaderFinished() ) and when it is replaced (onLoaderReset() ).
My onActivityCreated(Bundle) method looks like this:
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mAccountsDbAdapter = new AccountsDbAdapter(getActivity().getApplicationContext());
setHasOptionsMenu(true);
mCursorAdapter = new AccountsCursorAdapter(getActivity()
.getApplicationContext(), R.layout.list_item_account, null,
new String[] { DatabaseHelper.KEY_NAME },
new int[] { R.id.account_name }, 0);
setListAdapter(mCursorAdapter);
getLoaderManager().initLoader(0, null, this);
}
Later on, the ListFragment is replaced with another Fragment B.
When the user presses the back button, Fragment B is removed and the ListFragment is added again. However, the list is empty and only the android:empty elements are displayed and none of the LoaderCallback methods are called. I can use the debugger to determine that getLoaderManager().initLoader(0, null, this); is actually called, but nothing else.
When I change it to getLoaderManager().restartLoader(0, null, this);, the callbacks get called, but still my list remains empty (although there is data, the view is not refreshed).
How can I get my ListFragment to refresh itself when it is returned to the layout?
Has anyone encountered this before, how did you fix it?
FYI, here are my callback methods
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new AccountsCursorLoader(this.getActivity()
.getApplicationContext());
}
@Override
public void onLoadFinished(Loader<Cursor> loaderCursor, Cursor cursor) {
mCursorAdapter.swapCursor(cursor);
mCursorAdapter.notifyDataSetChanged();
}
@Override
public void onLoaderReset(Loader<Cursor> arg0) {
mCursorAdapter.swapCursor(null);
}
Some notes:
- I cannot use the
setListShown(true)methods in the example because I get anIllegalStateExceptionthat it cannot be used with a custom content view. - My
AccountsCursorAdapterextends aSimpleCursorAdapterand modifies only thebindView()method.
Eureka!!! I found it (by accident, of course)
TL;DR;
In the AccountsListFragment, I now create my database adapter (
AccountsDatabaseAdapter) in theonCreate()method and close it in theonDestroy()method and it now works. Previously I was creating my adapter in theonActivityCreated()and closing inonDestroyView(). Note that I am not referring to theListAdapter, but rather to my database interfacingAccountsDbAdapter.Attempt at long explanation:
Well, I was doing this because I thought that getting context through
getActivity()will not be possible in theonCreate()method. It turns out you cangetActivity()even beforeonActivityCreated()is called.But I cannot really explain why this now works because the
Loaderhas its ownDatabaseAdapterobject which it uses to retrieve the data. If I were to guess, I would say that the same database object is returned for both database adapters (the database is cached). Which would mean that when I close one inonDestroyView(), the other is also closed and the cursor data set becomes invalid which results in an empty list view. The loader does not reload because it thinks the data has not changed.But even this explanation does not satisfy me completely, because some of the suggested solutions here which I tried like force restarting the loader each time did not work. (in the
loadInBackground()method, a newDatabaseAdapteris created each time).Anyway, if you happen to have a better understanding of what is going on, please hammer away in the comments.
Thanks everyone for the help with this!