文中提及的 Loader 相关知识基于 supprot.v4 24.0.0 中的 Loader 相关源码,android framework 的基本大同小异。
简介
关于 LoaderManager,Android Developer 上写道:LoaderManager 是与 Activity 或 Fragment 相关联的抽象类,用于管理一个或多个 Loader 实例。LoaderManager 有助于管理与 Activity 或 Fragment 生命周期相关联的、运行时间较长的操作。最常见的用法是与 CursorLoader 一起使用,但应用可以使用自定义的 Loader 用于加载其他类型的数据。
那么 LoaderManager 到底是如何管理 Loader,又是做到与 Activity、Fragment 的生命周期关联呢?本文将围绕这两个问题进行探究。
LoaderManager 与 LoaderManagerImpl
LoaderManager 实际是一个抽象类
真正实现了 LoaderManager 的是 LoaderManagerImpl,FragmentActivity 中通过 getSupportLoaderManager() 和 Fragment 中 getLoaderManager() 返回的都是 LoaderManagerImpl 实例。所以,分析 LoaderManager 的机制离不开分析 LoaderManagerImpl。
源码分析
LoaderManager 的初始化
在 support.v4 中,LoaderManager 是通过 FragmentHostCallback 创建实例。
当我们调用 FragmentActivity.getSupportLoaderManager() 时,执行的代码如下:
|
|
其中 mHost 是初始化 FragmentController 时传进来的 FragmentHostCallback 的子类 HostCallbacks,对应的 getLoaderManagerImpl 方法代码为:
|
|
getLoaderManager(String,boolean,boolean) 方法负责实例化 LoaderManagerImpl 并且将它储存在 SimpleArrayMap 中,方便之后复用。
Fragment.getLoaderManager 也一样是通过 FragmentHostCallback 的 mHost.getLoaderManager 获取 LoaderManagerImpl 实例。
|
|
至此,则完成了 LoaderManagerImpl 的初始化工作。
Loader 的创建与启动
LoaderManager 中,每一个 Loader 都会有自己的 id,开发者可以后续通过该 id 获取 Loader 实例或者进行重启、销毁操作。
|
|
当对应 id 的 LoaderInfo 存在且数据加载已经完成时,会将对应的 Loader 以及数据会传递到 onLoadFinished 方法中。一般来说,两个加载不同数据的 Loader 不会使用相同的 id。若使用了相同的 id,需要注意的是必须先执行 LoaderManager.destroyLoader(int)
方法将前一个同 id 的 Loader
销毁掉,否则会发生异常。
举个例子,LoaderA 需要的数据对应的 class 为 A,LoaderB 则需要 B。当 LoaderA、LoaderB 的 id 都是 1 并且 LoaderA 先加载完成。若不调用 LoaderManager.destroyLoader(int)
,LoaderManager 会立即返回 A 到 LoaderB 对应的回调中,此时由于 LoaderB 需要的是 B,则会立即抛出
ClassCastException。
最好的做法是使用唯一的 id,这样就不需要关心太多这些细节。
当对应 id 的 LoaderInfo 不存在时,就会调用 createAndInstallLoader 创建 LoaderInfo 实例
|
|
可以看到,createAndInstallLoader 中实例化了 LoaderInfo 对象,并且调用了 initLoader 传进来的 LoaderCallbacks 的 onCreateLoader 方法,并赋值到 LoaderInfo 的 mLoader 中以供之后调用。创建完后调用 installLoader 方法将 LoaderInfo 存放到 mLoaders(SparseArray)中, 紧接着在 LoaderInfo 的 start 房中注册了 OnLoadCompleteListener 及 OnLoadCanceledListener 以监听 Loader 是否加载完成或取消加载,并调用 Loader 的 startLoading 方法开始加载数据。
|
|
当 onLoadCanceled、onLoadComplete 回调执行后,会判断相同 id 下是否存在其他未处理的 Loader,若未处理则按照正常的流程启动该 Loader 并销毁当前已处理完的 LoaderInfo(执行 onLoaderReset 回调)。与 onLoadCanceled 不同的是 onLoadComplete 还会通知 Loader 已经加载完成。
至此,LoaderManager 管理 Loader 的加载过程已粗略了解。当然,加载过程中还会有其他细节等(如 Loader 的状态,可参考此链接),有兴趣的话可以自己阅读源码。
生命周期关联
LoaderManager 与 Activity 的生命周期关联主要是通过在 Activity 的 onStart、onStop、onDestroy 方法中调用 FragmentController 的 doLoaderStart、doLoaderStop、doDestroy 等方法达到关联的目的。
|
|
类似 Activity,Fragment 中也是通过 onStart、onDestroy、performReallyStop(该方法会在 Fragment 进入 STOPPED 状态时调用)来进行关联。
|
|
最后
希望本文能帮助各位读者理解 LoaderManager 如何管理 Loader,以便使用 Loader 机制时能更得心应手。
(这篇文章断断续续地写了几个星期,算是第一次写较为深入源码的文章,有点力不从心。如果哪里有错、哪里写得不好,还望各位指出,谢谢。)