LoaderManager&Loader源码剖析(1) – Activity对LoaderManager的管理

来源:互联网 发布:怎样在淘宝上找优惠券 编辑:程序博客网 时间:2024/06/05 20:01

Loader从android 3.0以后引进来的,由于它可以在后台加载数据,因此对于应用的开发是比较重要的组成部分。正是这个原因,我才觉得有必要好好研究一下Loader一系列相关的东西。

 

在此之前,我们应该大概了解了Loader的使用,如果不太了解,可参考之前的文章。按照使用惯例,我们总是从Activity或者Fragment中获取LoaderManager来使用。因此,我们就从Activity.java中的LoaderManager开始分析。

 

先开始看一下Activity.java的onStart()方法: 

protected void onStart() {        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStart " + this);        mCalled = true;                if (!mLoadersStarted) {            mLoadersStarted = true;            if (mLoaderManager != null) {                mLoaderManager.doStart();            } else if (!mCheckedForLoaderManager) {                mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false);            }            mCheckedForLoaderManager = true;        }        getApplication().dispatchActivityStarted(this);    }


 mLoaderManager保存的是当前客户端通过方法getLoaderManager()返回的LoaderManager引用,它的赋值如下:

public LoaderManager getLoaderManager() {        if (mLoaderManager != null) {            return mLoaderManager;        }        mCheckedForLoaderManager = true;        mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true);        return mLoaderManager;    }

在onStart()里,如果发现mLoaderManager不为空,说明它已经被用户通过getLoaderManager()创建了,当前用户正在使用这个LoaderManager,那么需要调用它的doStart()方法来启动它。当然如果值为空,那么通过getLoaderManager(String who, boolean started, boolean create)方法来获取这个引用,这个调用其实和LoaderManager的恢复机制有关,其实是获得恢复的LoaderManager引用,关于恢复,本文后面有介绍。注意第3个参数create值为false,说明不会创建新的LoaderManager,它只是去查询获得引用。代码如下:

LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) {        if (mAllLoaderManagers == null) {            mAllLoaderManagers = new ArrayMap<String, LoaderManagerImpl>();        }        LoaderManagerImpl lm = mAllLoaderManagers.get(who);        if (lm == null) {            if (create) {                lm = new LoaderManagerImpl(who, this, started);                mAllLoaderManagers.put(who, lm);            }        } else {            lm.updateActivity(this);        }        return lm;    }

最终所有的引用都保存在了mAllLoaderManagers数组中。而在getLoaderManager()中调用的上面的同名方法,第3个参数传的是true,说明是需要创建一个LoaderManager实例的。而用户获得Activity或者Fragment的LoaderManager实例引用都是通过getLoaderManager()来实现的。


mCalled变量:如果你的自定义Activity没有调用super.onStart(),那么你会收到异常SuperNotCalledException的,这个异常是在performStart()抛出的。

其他变量应该不需要解释了。

 

接着我们看一下performStop()方法,这个方法是由ActivityThread类调用的,也是控制Activity生命周期的类, performXXX()方法会调用onXXX()方法,和Activity的生命周期是对应的方法,这个不难理解它的作用。

final void performStop() {        …….        if (mLoadersStarted) {            mLoadersStarted = false;            if (mLoaderManager != null) {                if (!mChangingConfigurations) {                    mLoaderManager.doStop();                } else {                    mLoaderManager.doRetain();                }            }        }……..}

 

mChangingConfigurations变量的作用也很简单:如果当前发生了配置变化,比如屏幕方向改变,语言改变等,这个变量就会被置为true,那么我们需要调用LoaderManager.doRetain()方法,表示需要保存当前的loaderManager,在Activity恢复时也要恢复这个LoaderManager。如果Activity的stop不是由于配置变化引起的,那么直接调用LoaderManager的doStop()方法,直接停止当前的LoaderManager。

 

还有一个与LoaderManager相关的地方就在performDestroy()方法里,如下:

final void performDestroy() {        mDestroyed = true;        mWindow.destroy();        mFragments.dispatchDestroy();        onDestroy();        if (mLoaderManager != null) {            mLoaderManager.doDestroy();        }}

 

上面调用mLoaderManager的doDestory()将其销毁了。这个LoaderManager的生命周期算是比较完整了。也许你会问,既然都已经销毁了,在Activity配置变化的时候这个LoadManager也没有保存下来啊,其实在doDestory()的实现里会去判断如果调用了doRetain(),那么就不会真正销毁这个LoaderManager。

 

当Activity需要重建的时候,必定需要保存mLoaderManager的引用啊,否则如何恢复这个LoaderManager呢,毕竟mLoaderManager = null了啊。其实机关就在方法retainNonConfigurationInstances()里,如下:

NonConfigurationInstances retainNonConfigurationInstances() {        Object activity = onRetainNonConfigurationInstance();        HashMap<String, Object> children = onRetainNonConfigurationChildInstances();        ArrayList<Fragment> fragments = mFragments.retainNonConfig();        boolean retainLoaders = false;        if (mAllLoaderManagers != null) {            // prune out any loader managers that were already stopped and so            // have nothing useful to retain.            final int N = mAllLoaderManagers.size();            LoaderManagerImpl loaders[] = new LoaderManagerImpl[N];            for (int i=N-1; i>=0; i--) {                loaders[i] = mAllLoaderManagers.valueAt(i);            }            for (int i=0; i<N; i++) {                LoaderManagerImpl lm = loaders[i];                if (lm.mRetaining) {                    retainLoaders = true;                } else {                    lm.doDestroy();                    mAllLoaderManagers.remove(lm.mWho);                }            }        }        if (activity == null && children == null && fragments == null && !retainLoaders) {            return null;        }                NonConfigurationInstances nci = new NonConfigurationInstances();        nci.activity = activity;        nci.children = children;        nci.fragments = fragments;        nci.loaders = mAllLoaderManagers;        return nci;}

看上面的代码,其关键在于变量mAllLoaderManagers这个变量上面已经介绍过了,它保存了所有Activity中创建的LoaderManager引用,自然也包含了mLoaderManager引用了。这个方法会被ActivityThread类调用,而且早于performDestroy()方法调用。

 

这个方法会查看mAllLoaderManagers保存的所有引用,如果某个LoaderManagerImpl.mRetaining值为false的话,就会被remove掉。如果配置变化发生的话,mRetaining = true,当然mRetaining这个值是在performStop()中的doRetain()调用来设置的。

 

当mAllLoaderManagers处理完成后,别忘记将它的引用保存到nci.loaders中去,这样才能真正恢复。下面我们再来看一下它是如何恢复的呢?且看onCreate()方法:

protected void onCreate(Bundle savedInstanceState) {        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);        if (mLastNonConfigurationInstances != null) {            mAllLoaderManagers = mLastNonConfigurationInstances.loaders;        }

原来mAllLoaderManagers是从mLastNonConfigurationInstances中恢复的,而mLastNonConfigurationInstances的恢复其实是从onAttach()方法中开始的:

final void attach(Context context, ActivityThread aThread,            Instrumentation instr, IBinder token, int ident,            Application application, Intent intent, ActivityInfo info,            CharSequence title, Activity parent, String id,            NonConfigurationInstances lastNonConfigurationInstances,            Configuration config) {……mLastNonConfigurationInstances = lastNonConfigurationInstances;

接下来再看performStart方法:

final void performStart() {        mFragments.noteStateNotSaved();        mCalled = false;        mFragments.execPendingActions();        mInstrumentation.callActivityOnStart(this);        if (!mCalled) {            throw new SuperNotCalledException(                "Activity " + mComponent.toShortString() +                " did not call through to super.onStart()");        }        mFragments.dispatchStart();        if (mAllLoaderManagers != null) {            final int N = mAllLoaderManagers.size();            LoaderManagerImpl loaders[] = new LoaderManagerImpl[N];            for (int i=N-1; i>=0; i--) {                loaders[i] = mAllLoaderManagers.valueAt(i);            }            for (int i=0; i<N; i++) {                LoaderManagerImpl lm = loaders[i];                lm.finishRetain();                lm.doReportStart();            }        }    }

 

上面的代码通过调用LoaderManager.finishRetain()以及doReportStart()方法来恢复LoaderManager的状态。

 

好了,以上就是Activity针对LoaderManager的管理,而Loader的管理自然是LoaderManager的事了。从上面的分析可以看出,Activity和LoaderManager的职能划分很清晰,这也大大简化了Loaders的管理。

 


0 0