天天看点

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

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的管理。