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的管理。
- LoaderManager&Loader源码剖析(1) – Activity对LoaderManager的管理
- LoaderManager&Loader源码剖析(2) – LoaderManager对Loader的主要管理
- LoaderManager
- LoaderManager
- Android中Loader及LoaderManager的使用
- Android中Loader及LoaderManager的使用
- Android Loader and LoaderManager
- Developer--Loader-LoaderManager
- Android中Loader及LoaderManager的使用(附源码下载)
- Android中Loader及LoaderManager的使用(附源码下载)
- Android中Loader及LoaderManager的使用(附源码下载)
- 深入源码解析Android中Loader、AsyncTaskLoader、CursorLoader、LoaderManager
- Android_Loader_使用LoaderManager管理Loader实现异步动态加载数据
- Android_Loader_使用LoaderManager管理Loader实现异步动态加载数据
- Android_Loader_使用LoaderManager管理Loader实现异步动态加载数据
- 【Android】使用LoaderManager管理Loader实现异步动态加载数据
- AndroidのLoaderManager管理Loader实现异步动态加载数据
- 使用LoaderManager管理Loader实现异步动态加载数据
- Magento获取当前Collection的排序方式
- Unity和android通信
- 让图片在页面中飘浮
- tomcat8 下访问jsp,报告serverlet fillter出错
- Could not execute JDBC batch update
- LoaderManager&Loader源码剖析(1) – Activity对LoaderManager的管理
- spring mvc json @ResponseBody 出现406错误 not acceptable ,解决方法,亲测可行
- sharedpreference中putStringSet和getStringSet的问题
- Qt:内建对话框
- php之字符串处理
- 杭电2072 单词数
- How to install GSL on linux (ubuntu)
- 【BZOJ】【P2258】【pku2758 Checking the Text 文本校对】【题解】【hash】
- Eclipse的命令行输入