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