前言
前面已经学习了CursorLoader的代码实现,但是对于它如何集成到Activity/Fragment中还是有些迷惑的,好在Android提供了LoaderManager的代码实现,通过阅读LoaderManager实现可以更好的理解Loader的整体工作机制。
LoaderManager抽象类
LoaderManager首先定义的是一个回调接口,这个接口专门用来给使用Loader的用户实现,其中的泛型类D是实际返回的数据类型。
public interface LoaderCallbacks<D> {
// 根据指定的id和参数创建Loader对象,对于CursorLoader,
// 这里创建的就是CursorLoader对象, 其中的D是Cursor类型
public Loader<D> onCreateLoader(int id, Bundle args);
// 当数据请求成功会将请求的Loader对象和数据回调
public void onLoadFinished(Loader<D> loader, D data);
// 当Loader被重置会回调方法
public void onLoaderReset(Loader<D> loader);
}
接下来的几个抽象方法都是提供给用户使用的:
// 初始化一个loader对象
public abstract <D> Loader<D> initLoader(int id, Bundle args,
LoaderManager.LoaderCallbacks<D> callback);
// 重新启动一个loader对象
public abstract <D> Loader<D> restartLoader(int id, Bundle args,
LoaderManager.LoaderCallbacks<D> callback);
// 销毁一个loader对象
public abstract void destroyLoader(int id);
它们具体的实现还要查看LoaderManagerImpl类里的代码。
LoaderManagerImpl实现类
LoaderManagerImpl的成员变量包含:
// 记录当前处于活跃状态的Loader,它会在从开始请求到被显示停止
// 或者被重新开始请求
final SparseArray<LoaderInfo> mLoaders = new SparseArray<LoaderInfo>(0);
// 当用户重新启动当前的loader,之前有一个loader正在执行,那么
// 之前的旧loader就会被abandon然后放到这个成员里,它会在
// onLoadComplete完成之后被清除,这个对象存在主要是为了在
// 新Loader请求到数据之前可以使用旧Loader已经请求到的数据
// (不是很懂?)
final SparseArray<LoaderInfo> mInactiveLoaders = new SparseArray<LoaderInfo>(0);
// 是activity的话是"(root)",如果是Fragment还会有fragment的标签
final String mWho;
// 当前界面是否处于onStart和onStop之间的状态
boolean mStarted;
// 当Activity在后台被回收或者配置发生变化比如Activity横竖屏切换情况下
// 保存Loader的实例,以便在新产生的Activity里恢复原来的状态
boolean mRetaining;
boolean mRetainingStarted;
// 是否正在创建Loader
boolean mCreatingLoader;
// 包含Fragment相关的回调对象
private FragmentHostCallback mHost;
在LoaderManager的实现里,还是对Loader做了进一步的封装LoaderInfo,里面包含了Loader的状态控制和回调实现。
final class LoaderInfo implements Loader.OnLoadCompleteListener<Object>,
Loader.OnLoadCanceledListener<Object> {
// Loader对应的id
final int mId;
// 创建loader时候传递的参数
final Bundle mArgs;
// loader请求成功或者被取消后回调接口,用户传递进来的
LoaderManager.LoaderCallbacks<Object> mCallbacks;
// 生成的loader对象实例
Loader<Object> mLoader;
// 当前loaderInfo是否包含数据
boolean mHaveData;
boolean mDeliveredData;
// 请求到的数据对象缓存
Object mData;
// loader相关的状态标识
boolean mStarted;
boolean mRetaining;
boolean mRetainingStarted;
boolean mReportNextStart;
boolean mDestroyed;
boolean mListenerRegistered;
// 假如有Loader实例正在请求,但是还未完全取消或者完成执行
// 这时用户发出了新的网络请求,需要等待旧的请求结束才会开始
// 新的请求,mPendingLoader就是用来暂存这个新请求产生的loader实例
LoaderInfo mPendingLoader;
// 构造函数,保存下用户请求传入的3个参数
public LoaderInfo(int id, Bundle args, LoaderManager.LoaderCallbacks<Object> callbacks) {
mId = id;
mArgs = args;
mCallbacks = callbacks;
}
...
}
这里先介绍LoaderInfo包含的成员变量,至于它的方法则需要通过LoaderManagerImpl的方法initLoader和restartLoader两个方法来调用,initLoader相对比较简单只是开始一个新的请求,不涉及旧的请求取消操作,所以如果有旧的loader正在请求,只是最终的回调会变成initLoader新传入的回调接口;restartLoader却会将旧的Loader完全取消,不再使用里面任何信息。这里先分析initLoader方法的实现。
public <D> Loader<D> initLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback) {
if (mCreatingLoader) {
throw new IllegalStateException("Called while creating a loader");
}
LoaderInfo info = mLoaders.get(id);
// 检查是否有旧的loader正在运行
if (info == null) {
// 没有旧的loader,创建并且将其放到mLoaders里
info = createAndInstallLoader(id, args, (LoaderManager.LoaderCallbacks<Object>)callback);
} else {
// 替换掉旧Loader的回调接口,比如用户旋转屏幕导致
// Activity被重新创建,之前有一个loader正在运行,它的回调
// 就是针对旧Activity做处理,这时需要用新的Activity里的回
// 调替换掉
info.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback;
}
// 如果旧的Loader已经请求到了数据直接回调onLoadFinsh
if (info.mHaveData && mStarted) {
info.callOnLoadFinished(info.mLoader, info.mData);
}
return (Loader<D>)info.mLoader;
}
创建Loader的实现代码如下:
// 创建并将loader注册到mLoaders
private LoaderInfo createAndInstallLoader(int id, Bundle args,
LoaderManager.LoaderCallbacks<Object> callback) {
try {
mCreatingLoader = true;
// 创建loader实例
LoaderInfo info = createLoader(id, args, callback);
// 注册loader实例
installLoader(info);
return info;
} finally {
mCreatingLoader = false;
}
}
// 创建Loader
private LoaderInfo createLoader(int id, Bundle args,
LoaderManager.LoaderCallbacks<Object> callback) {
// 生成loader请求的包装loaderInfo实例
LoaderInfo info = new LoaderInfo(id, args, (LoaderManager.LoaderCallbacks<Object>)callback);
// 调用onCreateLoader产生真实的loader
Loader<Object> loader = callback.onCreateLoader(id, args);
info.mLoader = (Loader<Object>)loader;
return info;
}
// 安装注册实例
void installLoader(LoaderInfo info) {
// 将loadInfo放入mLoaders
mLoaders.put(info.mId, info);
// 如果界面处于mStarted状态,直接开始请求
if (mStarted) {
info.start();
}
}
从创建注册loader的代码可知在loaderManager处于mStarted状态时会直接启动Loader做异步请求加载,getLoaderManager().initLoader是用户调用的接口,那么LoaderManger又在什么情况下会处于mStarted=true的状态呢,现在从Activity的getLoaderManager => FragmentHostCallback.getLoaderManager。
// LoaderManagerImpl的构造函数
LoaderManagerImpl(String who, FragmentHostCallback host, boolean started) {
mWho = who;
mHost = host;
mStarted = started;
}
// FragmentHostCallback获取LoaderManager的方法
LoaderManagerImpl getLoaderManagerImpl() {
if (mLoaderManager != null) {
return mLoaderManager;
}
mCheckedForLoaderManager = true;
// 在Activity里这个who就是"(root)", mLoaderStarted就直接赋值给mStarted
mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true /*create*/);
return mLoaderManager;
}
LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) {
if (mAllLoaderManagers == null) {
mAllLoaderManagers = new ArrayMap<String, LoaderManager>();
}
LoaderManagerImpl lm = (LoaderManagerImpl) mAllLoaderManagers.get(who);
// 第一次调用实例化LoaderManagerImpl对象
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;
}
查看FragmentHostCallback中对mLoaderStarted=true的代码,在doLoaderStart方法里,在Activity里查看调用doLoaderStart的方法代码:
// FragmentHostCallback的doLoaderStart方法
void doLoaderStart() {
if (mLoadersStarted) {
return;
}
// 设置loaderStarted
mLoadersStarted = true;
if (mLoaderManager != null) {
mLoaderManager.doStart();
} else if (!mCheckedForLoaderManager) {
mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false);
}
mCheckedForLoaderManager = true;
}
// FragmentHostCallback的doLoaderStop方法
void doLoaderStop(boolean retain) {
mRetainLoaders = retain;
if (mLoaderManager == null) {
return;
}
if (!mLoadersStarted) {
return;
}
mLoadersStarted = false;
if (retain) {
mLoaderManager.doRetain();
} else {
mLoaderManager.doStop();
}
}
// Activity的onStart方法
@CallSuper
protected void onStart() {
mCalled = true;
// 在这里调用了doLoaderStart方法
mFragments.doLoaderStart();
...
}
// Activity的performStop方法
final void performStop(boolean preserveWindow) {
mDoReportFullyDrawn = false;
mFragments.doLoaderStop(mChangingConfigurations /*retain*/);
...
}
可见在Activity的onStart中调用了LoaderManagerImpl.dostart,在performStop中调用了LoaderMangerImpl.doStop/doRetain,这里主要探讨loader的执行过程,不再详细讨论retain的问题。
void doStart() {
if (mStarted) {
RuntimeException e = new RuntimeException("here");
e.fillInStackTrace();
return;
}
// 设置当前的loaderManagerIpml为mStarted状态为true
mStarted = true;
// 调用注册的LoaderInfo.start方法
for (int i = mLoaders.size()-1; i >= 0; i--) {
mLoaders.valueAt(i).start();
}
}
void doStop() {
if (!mStarted) {
RuntimeException e = new RuntimeException("here");
e.fillInStackTrace();
return;
}
// 调用注册的LoaderInfo.stop方法
for (int i = mLoaders.size()-1; i >= 0; i--) {
mLoaders.valueAt(i).stop();
}
// 设置当前的loaderManagerIpml为mStarted状态为false
mStarted = false;
}
LoaderManagerImpl的doStart和doStop方法又回调了LoaderInfo的start和stop方法。
void start() {
...
mStarted = true;
if (mLoader == null && mCallbacks != null) {
// 如果没有生成Loader对象,创建loader对象
mLoader = mCallbacks.onCreateLoader(mId, mArgs);
}
if (mLoader != null) {
...
if (!mListenerRegistered) { // 为loader注册回调
// 注册请求成功的回调
mLoader.registerListener(mId, this);
// 注册取消加载的回调
mLoader.registerOnLoadCanceledListener(this);
mListenerRegistered = true;
}
// 开始异步加载操作
mLoader.startLoading();
}
}
CusorLoader的代码已经解析过了,在这里会调用onStartLoading方法,如果没有缓存就会执行后台加载,加载如果成功就会回调deliveryResult方法,而deliveryResult方法里就回调了onLoadComplete回调,查看LoadInfo的onLoadeComplete回调:
@Override
public void onLoadComplete(Loader<Object> loader, Object data) {
...
// 如果当前的Loader被取消而且有新的挂起Loader,
// 取消当前Loader后执行挂起的Loader请求
LoaderInfo pending = mPendingLoader;
if (pending != null) {
mPendingLoader = null;
mLoaders.put(mId, null);
destroy();
installLoader(pending);
return;
}
// 如果请求的数据与缓存数据不同,调用callOnLoadFinished
if (mData != data || !mHaveData) {
mData = data;
mHaveData = true;
if (mStarted) {
callOnLoadFinished(loader, data);
}
}
...
}
void callOnLoadFinished(Loader<Object> loader, Object data) {
if (mCallbacks != null) {
...
try {
// 回调用户传递进来的onLoadFinshed接口
mCallbacks.onLoadFinished(loader, data);
} finally {
if (mHost != null) {
mHost.mFragmentManager.mNoTransactionsBecause = lastBecause;
}
}
mDeliveredData = true;
}
}
在查看在LoaderManagerImpl.doStop时调用的stop方法,它主要是取消了注册的监控器,也就是说在onStop之后即使Loader请求成功也不会触发回调,同时调用了stopLoading方法。
void stop() {
if (DEBUG) Log.v(TAG, " Stopping: " + this);
mStarted = false;
if (!mRetaining) {
if (mLoader != null && mListenerRegistered) {
// Let the loader know we're done with it
mListenerRegistered = false;
mLoader.unregisterListener(this);
mLoader.unregisterOnLoadCanceledListener(this);
mLoader.stopLoading();
}
}
}
CursorLoader会在onStopLoad里调用cancelLoad最终又回调到onLoadCancelled方法。
@Override
public void onLoadCanceled(Loader<Object> loader) {
// 如果有挂起的请求loader,取消当前loader之后
// 再开始挂起的loader请求
...
LoaderInfo pending = mPendingLoader;
if (pending != null) {
mPendingLoader = null;
mLoaders.put(mId, null);
destroy();
installLoader(pending);
}
// 如果没有挂起的新请求什么都不做
}
这个mPendingLoader又是从哪里出现的呢,它其实是restartLoader里用来暂存新请求的对象。在开始一个Loader请求之后并且这个Loader依然在执行中,这时用户restartLoader开始新的Loader请求,新请求不能立即执行,需要等到取消旧的Loader执行完成,这时新的Loader请求就被挂起mPendingLoader保存了它的引用,等到旧loader完全结束在onLoadComplete或onLoadCancelled就代表旧Loader执行完成了,在这两个回调里在开始新的Loader异步请求。
public <D> Loader<D> restartLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback) {
if (mCreatingLoader) {
throw new IllegalStateException("Called while creating a loader");
}
// 获取最上一次开始请求的Loader
LoaderInfo info = mLoaders.get(id);
if (info != null) { // 如果已经启动过Loader
// 查看是否有目前已经被abandon的旧Loader
LoaderInfo inactive = mInactiveLoaders.get(id);
if (inactive != null) { // 如果存在有abandon的旧Loader
if (info.mHaveData) { // 如果当前Loader已经请求完成
// 销毁之前已经abandon的loader
inactive.mDeliveredData = false;
inactive.destroy();
// 将当前loader abandon并且替换旧abandon的loader
info.mLoader.abandon();
mInactiveLoaders.put(id, info);
} else { // 如果当前启动的loader还未完全执行完毕
// 但是当前启动的loader还未被取消,直接销毁
if (!info.cancel()) {
mLoaders.put(id, null);
info.destroy();
} else {
// 当前启动的loader正在取消过程中
if (info.mPendingLoader != null) {
// 已有待启动的新请求,这个还没启动的直接销毁
info.mPendingLoader.destroy();
info.mPendingLoader = null;
}
// 将本次请求的Loader作为最新的挂起Loader对象,等
// 到被取消的Loader完成后会在回调里启动挂起的Loader请求
info.mPendingLoader = createLoader(id, args,
(LoaderManager.LoaderCallbacks<Object>)callback);
return (Loader<D>)info.mPendingLoader.mLoader;
}
}
} else {
// 如果没有待取消的旧Loader,直接废弃当前Loader
info.mLoader.abandon();
mInactiveLoaders.put(id, info);
}
}
// 如果没有等待取消完成的Loader,立即开始新的loader请求
info = createAndInstallLoader(id, args, (LoaderManager.LoaderCallbacks<Object>)callback);
return (Loader<D>)info.mLoader;
}
截止到目前Loader整体的启动过程已经基本过了一遍,还是有不少细节有待发掘,了解了Loader与Activity生命周期联动关系,就能够更好的使用Loader框架进行开发。