简单研究Loader笔记

2015-11-11 18:25:34

1. Loader是什么?

/**
 * Static library support version of the framework's {@link android.content.Loader}.
 * Used to write apps that run on platforms prior to Android 3.0.  When running
 * on Android 3.0 or above, this implementation is still used; it does not try
 * to switch to the framework's implementation.  See the framework SDK
 * documentation for a class overview.
 */

Loader是2011年Android3.0以后引入的一种加载数据的方式,至于是异步还是同步,这取决于你怎么实现。

2. Loader其实是一种框架,它本身什么功能都没有,但是你能很方便的利用这个框架搭建自己的代码,而且搭建好之后,怎么运行,你也不用关心,等待结果就OK了。那么Loader是一种怎样的框架呢?我们先来搞清楚他是怎么用的,然后再去看他的框架。

 1 //可以在Activity或者Fragment中调用
 2 getSupportLoaderManager().restartLoader(1, null, new LoaderCallback());
 3 
 4 //实现一个LoaderCallbacks
 5 public class RxLoaderCallback<D> implements LoaderManager.LoaderCallbacks<D> {
 6     public RxLoaderCallback(Context context) {
 7     }
 8 
 9     @Override
10     public Loader<D> onCreateLoader(int id, Bundle args) {
11         //创建Loader
12         return new Loader();
13     }
14 
15     @Override
16     public void onLoadFinished(Loader<D> loader, D data) {
17     //Loader执行完成后,返回的结果数据和执行的loader
18     }
19 
20     @Override
21     public void onLoaderReset(Loader<D> loader) {
22     //Loader被重置,此时Loader的数据处于不可用状态,因此任何使用此Loader数据的引用,都应该重置自己
23     }
24 }
25 
26 //重写一个Loader
27 /**
28  * Created by David on 15/11/11.
29  */
30 public class RxLoader<D> extends Loader<D> {
31     public RxLoader(Context context, Observable<D> observable) {
32         super(context);
33     }
34 
35     @Override
36     protected void onStartLoading() {
37         //你要做的任务
38         super.onStartLoading();
39         deliverResult(mData);
40     }
41 }

这是一个简单的使用,这个框架最核心的东西就是onStartLoading()方法,这里就是你要执行的任务,任务执行结束后,记得调用deliverResult(mData),将结果抛出去。

3. 进入Loader的框架

3.1 读Loader源码,发现实现这套机制最核心的有四个方法:

1 startLoading() //不需要你调用,是用来启动这个Loader的
2 onStartLoading() //前面说到了
3 deliverResult(D data) //抛出结果
4 registerListener(int id, OnLoadCompleteListener<D> listener) //也不需要你调用,注册一个Listener,执行完成后,抛出结果

事实上,这两个不需要我们来调用的方法是由LoaderManager来调用的,也就是说,当你使用initLoader或者restartLoader的时候被调用的。源码如下:

1     public final void startLoading() {
2         mStarted = true;
3         mReset = false;
4         mAbandoned = false;
5         onStartLoading();
6     }

本质上还是调用了我们实现的onStartLoading()方法。那么,执行完成后的结果是怎么抛出来的呢?这就是deliverResult(D data)干的事情了,源码:

1     public void deliverResult(D data) {
2         if (mListener != null) {
3             mListener.onLoadComplete(this, data);
4         }
5     }

而这个mListener就是通过registerListener()方法注册的,同样是由LoaderManager注册,所以LoaderManager中会获得结果,然后调用LoaderCallback的onLoadFinished()方法。但是,有一个问题,按照常规,执行得到结果后应该自动调用mListener.onLoadComplete()方法,但是Loader没有自己调用,必须由我们来触发。有点让人费解,不过我的理解是,Loader框架默认是一个同步的框架,而且这不是一个“很完整”的框架,留下了足够的灵活性,便于我们自己定制。

3.2 总结一下:

     LoaderCallback的作用很明显,就是起到创建Loader和提供回调方法的作用,同时,Loader的onStartLoading()供子类实现,其实这里做成一个抽象方法更好~用来执行真正的任务,同时把结果抛出去。

4. 进入LoaderManager

4.1 我们是通过getSupportLoaderManager().restartLoader(1, null, new LoaderCallback())来使用LoaderManager的,也就是说,是通过getSupportLoaderManager()来获取LoaderManager的,这个方法其实是FragmentActivity提供的,FragmentActivity继承自Activity,只出现在support v4包中,所以只有向下兼容1.6的时候,我们自己的Activity需要继承自FragmentActivity,同时使用getSupportLoaderManager(),如果只在3.0以上系统中使用,那么直接使用Activity中的getLoaderManager()就好了~为了避免重名,所以FragmentActivity才会改名为getSupportLoaderManager()的吧。

4.2 我们以support v4包中的LoaderManager为例,探究一下他的实现(一下出现的Loader、LoaderManager和LoaderCallback均是support v4包中的)。FragmentActivity在它代码的最后,添加了如下代码:

 1     // ------------------------------------------------------------------------
 2     // LOADER SUPPORT
 3     // ------------------------------------------------------------------------
 4     
 5     /**
 6      * Return the LoaderManager for this fragment, creating it if needed.
 7      */
 8     public LoaderManager getSupportLoaderManager() {
 9         if (mLoaderManager != null) {
10             return mLoaderManager;
11         }
12         mCheckedForLoaderManager = true;
13         mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true);
14         return mLoaderManager;
15     }
16     
17     LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) {
18         if (mAllLoaderManagers == null) {
19             mAllLoaderManagers = new SimpleArrayMap<String, LoaderManagerImpl>();
20         }
21         LoaderManagerImpl lm = mAllLoaderManagers.get(who);
22         if (lm == null) {
23             if (create) {
24                 lm = new LoaderManagerImpl(who, this, started);
25                 mAllLoaderManagers.put(who, lm);
26             }
27         } else {
28             lm.updateActivity(this);
29         }
30         return lm;
31     }

当然了,它使用的同样的是v4包中的LoaderManager。事实上LoaderManager是一个抽象类,因此我们通过getSupportLoaderManager获得的其实是他的一个实现类,名字叫LoaderManagerImpl,这两个类的代码写在同一个java文件中。LoaderManager中有如下方法:

 1 public abstract <D> Loader<D> initLoader(int id, Bundle args,
 2             LoaderManager.LoaderCallbacks<D> callback);
 3 
 4     public abstract <D> Loader<D> restartLoader(int id, Bundle args,
 5             LoaderManager.LoaderCallbacks<D> callback);
 6 
 7     public abstract void destroyLoader(int id);
 8 
 9     public abstract <D> Loader<D> getLoader(int id);
10 
11     public abstract void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args);
12 
13     public static void enableDebugLogging(boolean enabled) {
14         LoaderManagerImpl.DEBUG = enabled;
15     }
16 
17     public boolean hasRunningLoaders() { return false; }

下面我们着重看一下LoaderManagerImpl类,首先从他的initLoader和restartLoader开始。开始之前,先来解决一个问题,那就是initLoader和restartLoader的区别:

真正的区别在于:
1. initLoader,如果有缓存LoaderCache,那么传入的bundle参数被忽略,同时新传入的LoaderCallbacks会替换缓存LoaderCache的LoaderCallbacks,这种适用于共用Loader,同时不需要新参数的情况,比如Activity Configuration发生变化导致Activity被销毁、重建时。
2. restartLoader,每次都会创建新的Loader,除非有缓存LoaderCache,并且LoaderCache是活着的但是没有执行结果,那么会新创新一个LoaderNew,LoaderNew只有在LoaderCache执行结束时才会被启动,并且LoaderCache被销毁,产生的结果不会被抛出。

4.3 LoaderManager是如何启动Loader,数据是如何返回的?

当我们在调用initLoader()和restartLoader()的时候,会根据需求创建并启动Loader,同时给Loader注册一个OnLoadCompleteListener,如果Loader执行完任务后,调用onLoadComplete,至于触发这个回调,则需要我们自己来做,前面有提到过。当LoaderManager收到回调返回的数据后,再调用LoaderCallbacks的onLoaderFinished()方法。当然在实际代码中,LoaderManagerImpl又封装了一个LoaderInfo,同时有很多对状态处理的代码,但是主要流程就是如此。LoaderManagerImpl中代码如下:

4.4 销毁Loader

LoaderManager提供了destroyLoader(id)方法,根据id来销毁Loader。

5. AsyncTaskLoader

5.1 前面提到了,Loader是一个框架,而且默认是不支持的框架,而在实际开发中,我们需要的多是异步的调用,所以AsyncTaskLoader应用而生了。顾名思义,AsyncTaskLoader是一个异步调用的Loader,使用方式如下:

LoaderCallbacks和之前的例子是一样的,看看Loader的实现。

 1 public class RxLoader<D> extends AsyncTaskLoader<D> {
 2  private D mData;
 3 
 4  public RxLoader(Context context) {
 5      super(context);
 6  }
 7 
 8  @Override
 9  public D loadInBackground() {
10   //要执行的任务mData = DoSomething
11  return mData;
12  }
13 
14  @Override
15  protected void onStartLoading() {
16      super.onStartLoading();
17   forceLoad(); //必须调用,否则loadInBackground()不会被执行
18  }
19 }

可以看出,loadInBackground()就是我们自己必须实现的(该方式是abstract)、执行任务的地方,任务可以是一个网络请求或者是任何任务。返回结果什么的,都是在LoaderCallbacks中处理的。有一点要注意,在loadInBackground中不需要手动调用deliveryResult()了,只需要将执行结果返回即可。

5.2 进入看看AsyncTaskLoader框架是怎么实现的

从5.1的使用中我们可以发现,需要在onStartLoading中手动调用forceLoader,根据前面的分析,我们知道onStartLoading中应该是要执行的任务,所以需要手动调用forceLoader(),那么forceLoader到底做了些什么?forceLoader()方法在Loader中,主要调用了onForceLoader,因此我们真正要看的是AsyncTaskLoader中的onForceLoader()方法,代码如下:


如上(1)处的代码,如果当前Task已经存在,那么先干掉。(2)处代码,创建了一个LoaderTask,LoaderTask继承自ModernAsyncTask,其本质上是一个AsyncTask,那么为毛不直接用AsyncTask呢?Google的解释是:为了支持AsyncTaskLoader,从AsyncTask中拷贝了有用的代码,是因为要依赖的AsyncTask的一些微妙的行为在旧的平台是不可靠的~而且由于ModernAsyncTask还没不是最终实现,目前不对外公开,只为AsyncTaskLoader而生。明白了吧,AsyncTask在旧平台上不可靠,而AsyncTaskLoader是要兼容到v4的,啦啦啦

(3)处的代码,就是启动这个像AsyncTask的东西了,然后返回数据,至于不熟悉AsyncTask的同学,自己补脑吧。

最后一个问题:结果是怎么传出来的?记得前面说过,需要在onStartLoading中手动调用deliverResult方法,但是继承自AsyncTaskLoader的子类,好像并没有手动调用,why?其实AsyncTask的onPostExcute中已经调用了,就这么回事。

6. 目前团App项目中,结合Retrofit,继承Loader来使用的,思路也很简单。至于为什么不是继承AsyncTaskLoader呢,是因为Retrofit会自己处理异步的操作,所以没必要。

7. 关于Retrofit,请参考:简单研究下Retrofit

原文地址:https://www.cnblogs.com/wlrhnh/p/4957210.html