源码分析:Activity对LoaderManager的管理

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq475703980/article/details/80636468

本文主要从Loader入手, 去分析Loader使用、Loader的源码分析等,主要分为以下四篇:

本文基于原生的 Android8.0源码进行分析。以下是第二篇内容

Activity/Fragment对LoaderManager的管理

学会了Loader的使用后,就可以进入源码去更多的了解Loader了。

在实例代码中, 我们知道了,使用Loader, 就是从初始化Loader这么一行代码开始的:

 getLoaderManager().initLoader(1, null, this);

这一行代码使用起来简单, 但是却内有乾坤, Google给我们做了很多封装,比如getLoaderManager()得到的LoaderManager对象,是什么时候创建的, 在哪里创建的?initLoader, 是如何初始化我们想要的Loader的?

我们这里从Activity中的getLoaderManager()去分析源码, Fragment的源码流程和这个类似,跟一下源码就很明白了。

一、 Activity中创建LoaderManager 对象

Activity对LoaderManager的管理主要有涉及四个生命周期方法:

  • onStart()
  • performStop()
  • performDestory()
  • performStart()
1. Activity的onStart()方法中创建LoaderManager

首先看看onStart()方法:

@CallSuper
protected void onStart() {
    mCalled = true;

    mFragments.doLoaderStart();
    ...
}

跟进mFragments.doLoaderStart(), 最终进入了FragmentHostCallback.java:

void doLoaderStart() {
    if (mLoadersStarted) {
        return;
    }
    mLoadersStarted = true;

    if (mLoaderManager != null) {
        mLoaderManager.doStart();
    } else if (!mCheckedForLoaderManager) {
        mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false);
    }
    mCheckedForLoaderManager = true;
}

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

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

最终LoaderManager的实例引用保存在了mAllLoaderManagers这个ArrayMap集合里面。

2. Activity的performStop()方法中停止LoaderManager

关键代码如下:

final void performStop(boolean preserveWindow) {
  ......
    mFragments.doLoaderStop(mChangingConfigurations /*retain*/);
  ......
}

注意到调用停止LoaderManager时,这里传入了mChangingConfigurations这个boolean类型的参数, 看一下它的声明:

/** true if the activity is being destroyed in order to recreate it with a new configuration */
/*package*/ boolean mChangingConfigurations = false;

就是说如果activity被销毁然后重建的话, 这个值就会为true, 这种情况有:切换横竖屏、修改语言等。 这个值仅在一处地方被设置为true, 就是在ActivityThread中的handleRelaunchActivity方法内:

private void handleRelaunchActivity(ActivityClientRecord tmp) {
......
r.activity.mChangingConfigurations = true;
......
}

继续跟进代码, 最终又进入FragmentHostCallback这个中间类,这个中间类的作用就是连接Activity/Fragment和LoaderManager, 从而将Activity/Fragment和LoaderManager之间的耦合降到最低,这种代码的设计就是迪米特法则的使用, 还是看代码吧:

void doLoaderStop(boolean retain) {
    mRetainLoaders = retain;

    if (mLoaderManager == null) {
        return;
    }

    if (!mLoadersStarted) {
        return;
    }
    mLoadersStarted = false;

    if (retain) {
        mLoaderManager.doRetain();
    } else {
        mLoaderManager.doStop();
    }
}

这里的retain实际上就是上面我们传入的mChangingConfigurations这个boolean值, 并进行了判断, 如果是true, 及有Activity的销毁再创建的过程存在,则调用doRetain()把LoaderManager存起来, 否则直接调用doStop。这里存起来就是为了在Activity再创建时,直接恢复LoaderManager对象。

3. Activity的performDestory()
final void performDestroy() {
    mDestroyed = true;
    mWindow.destroy();
    mFragments.dispatchDestroy();
    onDestroy();
    mFragments.doLoaderDestroy();
    if (mVoiceInteractor != null) {
        mVoiceInteractor.detachActivity();
    }
}

最终调用到LoaderManager的doDestroy()方法:

void doDestroy() {
    if (!mRetaining) {
        if (DEBUG) Log.v(TAG, "Destroying Active in " + this);
        for (int i = mLoaders.size()-1; i >= 0; i--) {
            mLoaders.valueAt(i).destroy();
        }
        mLoaders.clear();
    }

    if (DEBUG) Log.v(TAG, "Destroying Inactive in " + this);
    for (int i = mInactiveLoaders.size()-1; i >= 0; i--) {
        mInactiveLoaders.valueAt(i).destroy();
    }
    mInactiveLoaders.clear();
    mHost = null;
}

在这里,进行了判断,如果不是需要恢复状态的,就清除了LoaderManager所管理的Loader。否则不会清除

4. Activity的performStart()方法
final void performStart() {
    mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
    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();
    mFragments.reportLoaderStart();

...

}

在重新创建的Activity通过mFragments.reportLoaderStart() 恢复了LoaderManager。

二、 LoaderManager的恢复

切换横竖屏或者语言后, Activity会销毁重建一次, 也会对LoaderManager进行恢复, 恢复的方法在Activity的retainNonConfigurationInstances()方法中:

NonConfigurationInstances retainNonConfigurationInstances() {
    Object activity = onRetainNonConfigurationInstance();
    HashMap<String, Object> children = onRetainNonConfigurationChildInstances();
    FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();

    // We're already stopped but we've been asked to retain.
    // Our fragments are taken care of but we need to mark the loaders for retention.
    // In order to do this correctly we need to restart the loaders first before
    // handing them off to the next activity.
    mFragments.doLoaderStart();

......
}

Activity对LoaderManager的管理就说完了, 下一篇将分析LoaderManager对Loader的管理。

猜你喜欢

转载自blog.csdn.net/qq475703980/article/details/80636468
今日推荐