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是一种怎样的框架呢?我们先来搞清楚他是怎么用的,然后再去看他的框架。

 //可以在Activity或者Fragment中调用
getSupportLoaderManager().restartLoader(1, null, new LoaderCallback()); //实现一个LoaderCallbacks
public class RxLoaderCallback<D> implements LoaderManager.LoaderCallbacks<D> {
public RxLoaderCallback(Context context) {
} @Override
public Loader<D> onCreateLoader(int id, Bundle args) {
//创建Loader
return new Loader();
} @Override
public void onLoadFinished(Loader<D> loader, D data) {
//Loader执行完成后,返回的结果数据和执行的loader
} @Override
public void onLoaderReset(Loader<D> loader) {
//Loader被重置,此时Loader的数据处于不可用状态,因此任何使用此Loader数据的引用,都应该重置自己
}
} //重写一个Loader
/**
* Created by David on 15/11/11.
*/
public class RxLoader<D> extends Loader<D> {
public RxLoader(Context context, Observable<D> observable) {
super(context);
} @Override
protected void onStartLoading() {
//你要做的任务
super.onStartLoading();
deliverResult(mData);
}
}

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

3. 进入Loader的框架

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

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

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

     public final void startLoading() {
mStarted = true;
mReset = false;
mAbandoned = false;
onStartLoading();
}

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

     public void deliverResult(D data) {
if (mListener != null) {
mListener.onLoadComplete(this, data);
}
}

而这个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在它代码的最后,添加了如下代码:

     // ------------------------------------------------------------------------
// LOADER SUPPORT
// ------------------------------------------------------------------------ /**
* Return the LoaderManager for this fragment, creating it if needed.
*/
public LoaderManager getSupportLoaderManager() {
if (mLoaderManager != null) {
return mLoaderManager;
}
mCheckedForLoaderManager = true;
mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true);
return mLoaderManager;
} LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) {
if (mAllLoaderManagers == null) {
mAllLoaderManagers = new SimpleArrayMap<String, LoaderManagerImpl>();
}
LoaderManagerImpl lm = mAllLoaderManagers.get(who);
if (lm == null) {
if (create) {
lm = new LoaderManagerImpl(who, this, started);
mAllLoaderManagers.put(who, lm);
}
} else {
lm.updateActivity(this);
}
return lm;
}

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

 public abstract <D> Loader<D> initLoader(int id, Bundle args,
LoaderManager.LoaderCallbacks<D> callback); public abstract <D> Loader<D> restartLoader(int id, Bundle args,
LoaderManager.LoaderCallbacks<D> callback); public abstract void destroyLoader(int id); public abstract <D> Loader<D> getLoader(int id); public abstract void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args); public static void enableDebugLogging(boolean enabled) {
LoaderManagerImpl.DEBUG = enabled;
} 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的实现。

 public class RxLoader<D> extends AsyncTaskLoader<D> {
private D mData; public RxLoader(Context context) {
super(context);
} @Override
public D loadInBackground() {
//要执行的任务mData = DoSomething
return mData;
} @Override
protected void onStartLoading() {
super.onStartLoading();
forceLoad(); //必须调用,否则loadInBackground()不会被执行
}
}

可以看出,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

简单研究Loader笔记的更多相关文章

  1. SQLSERVER2012 列存储索引的简单研究和测试

    SQLSERVER2012 列存储索引的简单研究和测试 SQLSERVER2012 列存储索引的简单研究和测试 看这篇文章之前可以先看一下下面这两篇文章: 列存储索引 http://www.cnblo ...

  2. 简单脱壳教程笔记(2)---手脱UPX壳(1)

    本笔记是针对ximo早期发的脱壳基础视频教程,整理的笔记. ximo早期发的脱壳基础视频教程 下载地址如下: http://down.52pojie.cn/%E5%90%BE%E7%88%B1%E7% ...

  3. SQLSERVER中的LOB页面简单研究

    SQLSERVER中的LOB页面简单研究 这篇文章和我另一篇文章是相辅相成的,在看<SQLSERVER2012 列存储索引的简单研究和测试>这篇文章之前希望大家先看一下这篇文章o(∩_∩) ...

  4. 关于BLOB/TEXT字段存储设计及性能的简单研究

    简单研究了一下BLOB/TEXT字段对数据库性能的影响,得到一个大概的结论:(未验证) 无论MySQL还是MSSQL,都可以通过把BLOB/TEXT数据存储在行外的方式提高性能 把BLOB/TEXT字 ...

  5. 读《Wireshark网络分析就这么简单》读书笔记

    晚上花了两个多小时看完这本书,记录下一些看书过程中的笔记. 一.问题:A和B 是否能正常通信? 两台服务器A和服务器B的网络配置 A                                  ...

  6. 对jQuery ajax三级级联的简单研究

    最近写程序的时候经常遇到使用ajax获取数据的问题,刚好昨天遇到ajax写三级级联问题,自己写了一个简单的级联.对于服务端获取数据的就不多写了,客户端的ajax发送请求我在这里详细说一下,因为我也没专 ...

  7. 简单研究下Retrofit

    2015-09-24 15:36:26 第一部分: 1. 什么是Retrofit? (点击图片有惊喜) 以上是来自官网的解释,言简意赅,咳咳,我就不翻译了~ 2. 如何使用Retrofit? 2.1 ...

  8. 简单研究Android View绘制三 布局过程

    2015-07-28 17:29:19 这一篇主要看看布局过程 一.布局过程肯定要不可避免的涉及到layout()和onLayout()方法,这两个方法都是定义在View.java中,源码如下: /* ...

  9. OpenGL的简单研究-开端

    一直想要学习的但是没有学习的东西,大学一直在等待这个时间,终于可以闲下来研究一下这个部分的内容了. 计算机图形学,让计算机处理各种图像的东西,里面也存在很多算法和数学知识,很值得研究的一个领域,之前一 ...

随机推荐

  1. 微信,qq,微博如何不用每次清缓存就能看到h5修改过的结果

    描述:每次在对js,和css进行修改,想要在微信,微博或则qq里面预览效果,会发现没有生效,那是因为这些客户端会将静态进行缓存,我们需要清理缓存才能看到修改过的效果,但是每次清理缓存会很麻烦,影响开发 ...

  2. Download Oracle Forms 6i

    To download Oracle Forms Developer 6i from Oracle click this link http://download.oracle.com/otn/nt/ ...

  3. Jboss配置之数据源密码配置密文--EncryptingDataSourcePasswords

    local-tx-datasource:最常用的数据源配置,该连接池的连接管理器是LocalTxConnectionManager,只支持本地事务,不适合做分布式事务.以mssql为例如下:如果密码按 ...

  4. web项目总结——通过jsp+servlet实现对oracle的增删改查功能

    1.DAO模式 分包:依次建立 entity:实体包,放的是跟oracle数据库中表结构相对应的对象的属性,也就是这个对象有什么 dao:增删改查接口,实现增删改查的具体方法 service:同dao ...

  5. jquery总结06-动画事件04-自定义动画

    .animate(params,[speed],[easing],[fn]) params,[speed],[easing],[fn]Options,Number/String,String,Func ...

  6. RDCManager(远程登录工具)

    1: 2: 3: 4: 5 6 写文不易,转载请注明出处:http://www.cnblogs.com/zszs/p/5662752.html

  7. 使用vs2010创建、发布、部署、调用 WebService

    原文地址:使用vs2010创建.发布.部署.调用 WebService作者:吴超 一 使用vs2010创建 WebService 1 打开VS2010,菜单    文件->新建->项目2 ...

  8. Deep Learning 25:读论文“Network in Network”——ICLR 2014

    论文Network in network (ICLR 2014)是对传统CNN的改进,传统的CNN就交替的卷积层和池化层的叠加,其中卷积层就是把上一层的输出与卷积核(即滤波器)卷积,是线性变换,然后再 ...

  9. ubuntu16.04中将python3设置为默认

    直接执行这两个命令即可: sudo update-alternatives --install /usr/bin/python python /usr/bin/python2 100 sudo upd ...

  10. 从github拉取项目到myeclipse本地

    1.首先拿到jacky-lulu分享的地址 https://github.com/jacky-lulu1/cxf_client 2.登录jacky-lulu账号,fork一份cxf_client到自己 ...