LoaderManager源码阅读

前言

前面已经学习了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框架进行开发。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值