zoukankan      html  css  js  c++  java
  • 简单研究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

  • 相关阅读:
    SpringMVC的文件上传
    关于SringMvc的参数的传递
    Myeclipse配置mybatis的xml自动提示
    SSM配置
    sql中truncate 、delete与drop区别
    局部变量和全局变量的调用
    java中 引用类型 和 基本类型 有何区别?
    mysql--select
    网站建设注意要点
    输入域名之后默认首页跳转到其他链接去
  • 原文地址:https://www.cnblogs.com/wlrhnh/p/4957210.html
Copyright © 2011-2022 走看看