Google建议我们getLoaderManager().initLoader(0, null, this);在Fragment中进行调用onActivityCreated
http://developer.android.com/reference/android/content/AsyncTaskLoader.html
但是,这会产生以下问题:在配置更改期间将调用onLoadFinished两次(旋转)
我们可以按如下方式模拟问题.
package org.yccheok.gui;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.actionbarsherlock.app.SherlockFragment;
public class HomeMenuFragment extends SherlockFragment implements LoaderManager.LoaderCallbacks<HomeMenuFragment.Infos> {
private static class InfosLoader extends AsyncTaskLoader<Infos> {
private Infos infos = null;
public InfosLoader(Context context) {
super(context);
}
@Override
public Infos loadInBackground() {
Log.i(TAG, "loadInBackground");
this.infos = Infos.newInstance();
return infos;
}
/**
* Handles a request to cancel a load.
*/
@Override
public void onCanceled(Infos infos) {
super.onCanceled(infos);
}
/**
* Handles a request to stop the Loader.
* Automatically called by LoaderManager via stopLoading.
*/
@Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
/**
* Handles a request to start the Loader.
* Automatically called by LoaderManager via startLoading.
*/
@Override
protected void onStartLoading() {
if (this.infos != null) {
Log.i(TAG, "deliverResult");
deliverResult(this.infos);
}
if (takeContentChanged() || this.infos == null) {
Log.i(TAG, "forceLoad");
forceLoad();
}
}
/**
* Handles a request to completely reset the Loader.
* Automatically called by LoaderManager via reset.
*/
@Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
// At this point we can release the resources associated with 'apps'
// if needed.
this.infos = null;
}
}
static class Infos {
private Infos() {
}
public static Infos newInstance() {
return new Infos();
}
}
@Override
public void onActivityCreated (Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.i(TAG, "onActivityCreated");
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
getLoaderManager().initLoader(0, null, this);
}
@Override
public Loader<Infos> onCreateLoader(int arg0, Bundle arg1) {
return new InfosLoader(this.getSherlockActivity());
}
@Override
public void onLoadFinished(Loader<Infos> arg0, Infos arg1) {
Log.i(TAG, "onLoadFinished! -> " + arg1);
}
@Override
public void onLoaderReset(Loader<Infos> arg0) {
}
public void reloadAfterOpenFromCloud() {
this.getLoaderManager().getLoader(0).onContentChanged();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.home_menu, container, false);
return v;
}
private static final String TAG = HomeMenuFragment.class.getSimpleName();
}
Run Code Online (Sandbox Code Playgroud)
I/HomeMenuFragment(14776): onActivityCreated
I/HomeMenuFragment(14776): forceLoad
I/HomeMenuFragment(14776): loadInBackground
I/HomeMenuFragment(14776): onLoadFinished! -> org.yccheok.gui.HomeMenuFragment$Infos@4195ad58
[Rotation happens right here]
I/HomeMenuFragment(14776): onActivityCreated
I/HomeMenuFragment(14776): onLoadFinished! -> org.yccheok.gui.HomeMenuFragment$Infos@4195ad58
I/HomeMenuFragment(14776): onLoadFinished! -> org.yccheok.gui.HomeMenuFragment$Infos@4195ad58
Run Code Online (Sandbox Code Playgroud)
据安卓:LoaderCallbacks.OnLoadFinished叫了两声,对建议方案的一个呼吁initLoader在onResume.
@Override
public void onActivityCreated (Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.i(TAG, "onActivityCreated");
//getLoaderManager().initLoader(0, null, this);
}
@Override
public void onResume()
{
super.onResume();
Log.i(TAG, "onResume");
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
getLoaderManager().initLoader(0, null, this);
}
Run Code Online (Sandbox Code Playgroud)
这是日志记录.它看起来OK,现在经过我们移动initLoader到onResume.
I/HomeMenuFragment(15468): onActivityCreated
I/HomeMenuFragment(15468): onResume
I/HomeMenuFragment(15468): forceLoad
I/HomeMenuFragment(15468): loadInBackground
I/HomeMenuFragment(15468): onLoadFinished! -> org.yccheok.gui.HomeMenuFragment$Infos@4195aed0
I/HomeMenuFragment(15468): onActivityCreated
I/HomeMenuFragment(15468): onResume
I/HomeMenuFragment(15468): onLoadFinished! -> org.yccheok.gui.HomeMenuFragment$Infos@4195aed0
Run Code Online (Sandbox Code Playgroud)
我在想
Rud*_*nos 11
为什么建议的解决方案有效
如果我们所说的getLoaderManager()在onActivityCreated()那么我们初始化变量Fragment.mLoaderManager.
结果我们mLoaderManager.doReportStart()打电话Fragment.performStart()给FragmentActivity.onStart():
void performStart() {
if (mChildFragmentManager != null) {
mChildFragmentManager.noteStateNotSaved();
mChildFragmentManager.execPendingActions();
}
mCalled = false;
onStart();
if (!mCalled) {
throw new SuperNotCalledException("Fragment " + this
+ " did not call through to super.onStart()");
}
if (mChildFragmentManager != null) {
mChildFragmentManager.dispatchStart();
}
if (mLoaderManager != null) {
mLoaderManager.doReportStart();
}
}
Run Code Online (Sandbox Code Playgroud)
这是第一次打电话的原因onLoadFinished().
后来FragmentActivity.onStart()我们打电话给lm.finishRetain()(见代码片段):
if (mAllLoaderManagers != null) {
LoaderManagerImpl loaders[] = new LoaderManagerImpl[mAllLoaderManagers.size()];
mAllLoaderManagers.values().toArray(loaders);
if (loaders != null) {
for (int i=0; i<loaders.length; i++) {
LoaderManagerImpl lm = loaders[i];
lm.finishRetain();
lm.doReportStart();
}
}
}
Run Code Online (Sandbox Code Playgroud)
它是二次调用的原因onLoadFinished().
好.现在考虑的情况下,当我们要求getLoaderManager().initLoader(0, null, this)在onResume():
如果我们做这样一来,我们就没有既没有mLoaderManager.doReportStart(),也不lm.finishRetain()之后onActivityCreated(),而是我们onLoadFinished()在呼叫initLoader():
public <D> Loader<D> initLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback) {
if (mCreatingLoader) {
throw new IllegalStateException("Called while creating a loader");
}
LoaderInfo info = mLoaders.get(id);
if (DEBUG) Log.v(TAG, "initLoader in " + this + ": args=" + args);
if (info == null) {
// Loader doesn't already exist; create.
info = createAndInstallLoader(id, args, (LoaderManager.LoaderCallbacks<Object>)callback);
if (DEBUG) Log.v(TAG, " Created new loader " + info);
} else {
if (DEBUG) Log.v(TAG, " Re-using existing loader " + info);
info.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback;
}
if (info.mHaveData && mStarted) {
// If the loader has already generated its data, report it now.
info.callOnLoadFinished(info.mLoader, info.mData);
}
return (Loader<D>)info.mLoader;
}
Run Code Online (Sandbox Code Playgroud)
您可以info.callOnLoadFinished()在此代码段中看到通话:
if (info.mHaveData && mStarted) {
// If the loader has already generated its data, report it now.
info.callOnLoadFinished(info.mLoader, info.mData);
}
Run Code Online (Sandbox Code Playgroud)
我觉得很清楚:)
| 归档时间: |
|
| 查看次数: |
8407 次 |
| 最近记录: |