I'd like to use a demo to show this:
enter code here
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button button = (Button) findViewById(R.id.button1);
button.setOnClickListener(buttonClickListener);
}
private OnClickListener buttonClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
startMyLoader();
}
};
private void startMyLoader() {
getLoaderManager().destroyLoader(0);
getLoaderManager().restartLoader(0, null, myLoaderListener);
}
/**
* The listener for the group metadata loader.
*/
private final LoaderManager.LoaderCallbacks<Cursor> myLoaderListener
= new LoaderCallbacks<Cursor>() {
@Override
public CursorLoader onCreateLoader(int id, Bundle args) {
return new CursorLoader(LoaderDemoActivity.this,
ContactsContract.Contacts.CONTENT_URI,
null, null, null, null);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
cursor.moveToPosition(-1);
if (cursor.moveToNext()) {
Context context = getApplicationContext();
CharSequence text = "Load finished!";
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
}
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
}
};
enter code here
After orientation changed, I clicked the button, the onCreateLoader can be called, but onLoadFinished will not be called.
It seems strange.
Thanks for help in advance.
I faced the same problem. Please make a try call this.getSupportLoaderManager() in onCreate. It solved my problem. Hope it will help you as well
I think I have found the reason.
In Activity onCreate, it will load all the LoaderMangers(of its own or its sub-Fragments) from NonConfigurationInstances.
if (mLastNonConfigurationInstances != null) {
mAllLoaderManagers = mLastNonConfigurationInstances.loaders;
}
And in Activity onStart, it will try to start its own LoaderManger.
if (!mLoadersStarted) {
mLoadersStarted = true;
if (mLoaderManager != null) {
mLoaderManager.doStart();
} else if (!mCheckedForLoaderManager) {
mLoaderManager = getLoaderManager(-1, mLoadersStarted, false);
}
mCheckedForLoaderManager = true;
}
But after config changed, mLoaderManager == null, so it will not start it. And here is the problem! If you try to start loader belong to this loaderManager, it will fail.
void installLoader(LoaderInfo info) {
mLoaders.put(info.mId, info);
if (mStarted) {
// The activity will start all existing loaders in it's onStart(),
// so only start them here if we're past that point of the activitiy's
// life cycle
info.start();
}
}
note the mStarted value which will be set 'true' when LoaderManager started.
And there is two ways to solve this problem.
call getLoaderManger() in onCreate(), it will re-assign the mLoaderManager and make it ready to be started in the subseuqent onStart().
public LoaderManager getLoaderManager() { if (mLoaderManager != null) { return mLoaderManager; } mCheckedForLoaderManager = true; mLoaderManager = getLoaderManager(-1, mLoadersStarted, true); return mLoaderManager; }
have the loader located in fragments. Because in Fragments' onStart(), it will start its own LoaderManager.
if (!mLoadersStarted) { mLoadersStarted = true; if (!mCheckedForLoaderManager) { mCheckedForLoaderManager = true; mLoaderManager = mActivity.getLoaderManager(mIndex, mLoadersStarted, false); } if (mLoaderManager != null) { mLoaderManager.doStart(); } }
You don't need to (neither ought to) destroy your Loader
in order to reload it. Loader
class is intended to be reusable.
Use initLoader
instead. eg.:
getLoaderManager().initLoader(0, null, myLoaderListener);
If you want to force reloading allready registered loader:
getLoaderManager().getLoader(0).forceLoad();
If you are not sure if the Loader
instance allready exists after configuration change event happened use initLoader
instead of getLoader
to retrieve your Loader
instance on which you can call forceLoad()
.
getLoaderManager().initLoader(0, null, myLoaderListener).forceLoad();
If you use support library then use forceLoad
even after first instantation - there is probably a bug - I remind myself there are some questions about it on this forum - try searching older posts.
Make sure you are not checking savedStateInfo
while using fragments before you call your loader in activity onCreate
@Override
public void onCreate(Bundle savedInstanceState) {
// used to not overlap fragments
if (savedInstanceState != null) {
return null;
}
loadFragments();
getSupportLoaderManager().restartLoader(LISTS_LOADER, null, this);
}
If you need to check for savedInstanceState
fragments anyway you can check for any class variable that should be created after loader finished loading, as activity gets destroyed when rotating, but raising from previous state when rotating back.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With