一、Loader简介:
(一)、Loader的概念:

装载器从android3.0开始引进。它使得在activity或fragment中异步加载数据变得简单。

当成批显示数据的时候,为了使用户体验更好,需要进行异步装载。也就是说,让未显示数据的ListView等UI组件或控件先显示,避免出现白屏的尴尬现象,同时在后台下载数据,等下载完成后再更新ListView组件。这样尽管用户不会立刻看到数据,但是也不至于网络速度缓慢或服务器响应不及时而造成假死现象。

装载器具有如下特性:

  • 它们对每个Activity和Fragment都有效;

  • 他们提供了异步加载数据的能力;

  • 它拥有一个数据改变通知机制,当数据源做出改变时会及时通知。 也就是可以监听数据源,一旦数据源发生变化,Loader会感知这些变化;

  • 当Cursor 发生变化时,会自动加载数据,因此并不需要再重新进行数据查询。

    android设计Loader的初衷是想让大家像CursorLoader的做法一样,通过loader去维护数据,每次启动loader时先检查有没有旧的数据并把旧的数据先deliver给用户,然后再考虑要不要重新加载新的数据。

(二)、装载器API概述:

在使用装载器时,会涉及很多类和接口们,在下表中对它们总结一下:

Class/Interface 说明
LoaderManager

一个抽像类,关联到一个Activity或Fragment,管理一个或多个装载器的实例。这帮助一个应用管理那些与Activity或Fragment的生命周期相关的长时间运行的的操作。最常见的方式是与一个CursorLoader一起使用,然而应用是可以随便写它们自己的装载器以加载其它类型的数据。

每个activity或fragment只有一个LoaderManager。但是一个LoaderManager可以拥有多个装载器。

LoaderManager.LoaderCallbacks 一个用于客户端与LoaderManager交互的回调接口。例如,你使用回调方法onCreateLoader()来创建一个新的装载器。
Loader(装载器) 一个执行异步数据加载的抽象类。它是加载器的基类。你可以使用典型的CursorLoader,但是你也可以实现你自己的子类。一旦装载器被激活,它们将监视它们的数据源并且在数据改变时发送新的结果。
AsyncTaskLoader 提供一个AsyncTask来执行异步加载工作的抽象类。
CursorLoader AsyncTaskLoader的子类,它查询ContentResolver然后返回一个Cursor。这个类为查询cursor以标准的方式实现了装载器的协议,它的游标查询是通过AsyncTaskLoader在后台线程中执行,从而不会阻塞界面。使用这个装载器是从一个ContentProvider异步加载数据的最好方式。相比之下,通过fragment或activity的API来执行一个被管理的查询就不行了。

二AsyncTaskLoader示例:

(一)、AsyncTaskLoader 实现数据加载的步骤:

1、窗体Activity要实现LoaderManager.LoaderCallbacks<Cursor>接口。至于继承于Activity还是FragmentActivity要看是否需要支持3.0以下的版本。如果需要兼容则继承与FragmentActivity。

2.创建LoaderManager对象,通过getLoaderManager()或getSupportLoaderManager()方法实现。如果是继承FragmentActivity,则使用getSupportLoaderManager()方法创建,否则使用前者即可。

3、初始化LoaderManager对象,调用initLoader()方法来初始化;

  • initLoader()方法有以下参数:
  1. 一个唯一ID来标识装载器
  2. 可选的参数,用于装载器初始化
  3. 一个LoaderManager.LoaderCallbacks的实现。被LoaderManager调用以报告装载器的事件。一般窗体都实现了这个接口,所以传的是它自己:this;
  • initLoader()保证一个装载器被初始化并激活.它具有两种可能的结果:
  1. 如果Id所指的装载器已经存在,那么这个装载器将被重用
  2. 如果装载器不存在,initLoader()就出发LoaderManager.LoaderCallbacks中的毁掉方法onCreateLoader()。这是实例化并返回一个新的Loader的地方

4、操作ListView空间对象:先findViewByID(),然后setAdapter();

【备注】此时必须使用SimpleCursorAdapter适配器,而构建适配器的时候,第三个参数Cursor设置为null,最后一个参数:flags必须是:CursAdapter.FLAG_REGISTER_CONTENT_OBSERVER。

5、自定义Loader,作为onCreateLoader()的返回值

  • 自定义Loader要继承于AsyncTaskLoader<Cursor>;
  • 必须有构造方法
  • 必须重写onStartLoading()、loadInBackground()、deliverResult()。而且要在onStartLoading中调用forceLoad()才能依次调用下一个即将执行的方法
  1. 在loadInBackground()方法中执行数据库查询,返回Cursor;
  2. 在deliverResult()方法中执行跟适配器交换数据的操作。adapter.swapCursor(data)。
SimpleCursorAdapter构造方法的参数讲解。
方法原型:new SimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to , int flags) ;
 
参数:
1)、Context context, 这个与 SimpleListItemFactory 相关的 ListView 所处运行上下文(context)。也就是这个 ListView 所在的 Activity。
2)、int layout, 显示 list item 的 布局文件。这个 layout 文件中至少要包含在 "to" 参数中命名的 views。
3)、Cursor c, 数据库的光标( Cursor )。如果 cursor 无效,则该参数可以为 null
4)、String[] from, 指定 column 中的哪些列的数据将绑定(显示)到 UI 中。如果 cursor 无效, 则该参数可为 null。
5)、int[] to, 指定用于显示 "from" 参数指定的数据列表的 views。 这些 views 必须都是 TextViews。 "from" 参数的前 N 个值(valus)和 "to" 参数的前 N 个 views 是一一对应的关系。如果 cursor 无效,则该参数可为 null。
6)、flags,用于定义适配器行为的标志位。
  • Flags used to determine the behavior of the adapter; may be any combination of FLAG_AUTO_REQUERY andFLAG_REGISTER_CONTENT_OBSERVER。
  • FLAG_AUTO_REQUERY(常量值:1 )从 API11 开始已经废弃。因为他会在应用程序的 UI 线程中执行游标查询操作, 导致响应缓慢甚至应用程序无响应(ANR)的错误。作为替代方案,请使用 LoaderManager 和 AsyncTaskLoader、CursorLoader。
  • 如果设置FLAG_REGISTER_CONTENT_OBSERVER(常量值:2),适配器会在Cursor上注册一个内容观测器,当通知到达时会调用 onContentChanged() 方法。
(二)、LoaderManager.LoaderCallbacks主要回调方法:
1、onCreateLoader() :初始化并返回一个新的Loader;
当你试图去操作一个装载器时(比如,通过initLoader()),会检查是否指定ID的装载器已经存在.如果它不存在,将会触发LoaderManager.LoaderCallbacks 的方法onCreateLoader();
 
2、onLoadFinished():当一个装载器完成了它的装载过程后被调用;
这个方法是在前面已创建的装载器已经完成其加载过程后被调用.这个方法保证会在应用到装载器上的数据被释放之前被调用;
 
3、onLoaderReset() :当一个装载器被重置而其数据无效时被调用。
        所谓Loader的重置,就是指Loader对象还保留,只是清除Loader中的数据,所以onLoaderReset()方法相当于Loader的销毁方法。因此在onLoaderReset()方法中会找到即将释放的数据的引用,并移除这些引用。移除引用后,GC才可以清除这些数据。

当一个已创建的装载器被重置从而使其数据无效时,此方法被调用.此回调使你能发现什么时候数据将被释放。你可以释放对它的引用。

(四)、AsyncTaskLoader中各个方法的执行顺序:

04-01 04:00:25.477: MainActivity: ==onCreate
04-01 04:00:25.701: LoaderCallbacks: ==onCreateLoader
04-01 04:00:25.705: AsyncTaskLoader: ==onStartLoading
04-01 04:00:25.709: AsyncTaskLoader: ==loadInBackground
04-01 04:00:25.721: AsyncTaskLoader: ==deliverResult
04-01 04:00:25.721: LoaderCallbacks: ==onLoadFinished
04-01 04:00:25.749: MainActivity: ==onStart
04-01 04:00:25.749: MainActivity: ==onResume
04-01 04:00:25.973: MainActivity: ==onCreateOptionsMenu

(五)、当另一个app修改了同一个数据源(如:共同使用的SDCard上的数据库)后AsyncTaskLoader中各个方法的执行顺序:

04-01 04:01:06.693: MainActivity: ==onPause
04-01 04:01:08.413: MainActivity: ==onStop
04-01 04:01:15.721: AsyncTaskLoader: ==onStartLoading
04-01 04:01:15.721: AsyncTaskLoader: ==loadInBackground
04-01 04:01:15.721: AsyncTaskLoader: ==deliverResult
04-01 04:01:15.721: LoaderCallbacks: ==onLoadFinished
04-01 04:01:15.757: MainActivity: ==onStart
04-01 04:01:15.757: MainActivity: ==onResume

(三)、示例代码:

publicclass MainActivity extends FragmentActivity implements LoaderManager.LoaderCallbacks<Cursor> {

private ListView listView_main;

private LoaderManager manager;

privatestatic SimpleCursorAdapter adapter;

@Override

protectedvoid onCreate(Bundle arg0) {

super.onCreate(arg0);

setContentView(R.layout.activity_main);

listView_main = (ListView) findViewById(R.id.listView_main);

manager = getSupportLoaderManager();

manager.initLoader(0, null, this);

adapter = new SimpleCursorAdapter(this, R.layout.item_listview_main,

null, new String[] { "_id", "title" }, newint[] {

R.id.text_item_title, R.id.text_item_content }, 2);

listView_main.setAdapter(adapter);
} @Override public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) { Log.i("Activity", "===onCreateLoader"); returnnew MyLoader(this); } @Override publicvoid onLoadFinished(Loader<Cursor> arg0, Cursor arg1) { Log.i("Activity", "===onLoaderFinished"); adapter.swapCursor(arg1); } @Override publicvoid onLoaderReset(Loader<Cursor> arg0) { Log.i("Activity", "===onLoaderReset"); } staticclass MyLoader extends AsyncTaskLoader<Cursor> { private Context context; public MyLoader(Context context) { super(context); this.context = context; } @Override protectedvoid onStartLoading() { super.onStartLoading(); Log.i("MyLoader", "===onStartLoading"); forceLoad(); } @Override public Cursor loadInBackground() { Log.i("MyLoader", "===loadInBackground"); MySQLiteDatabaseHelper dbHelper = new MySQLiteDatabaseHelper(); Cursor cursor = dbHelper.selectCursor( "select id as _id , title from android_info limit 0,20", null); deliverResult(cursor); return cursor; } @Override publicvoid deliverResult(Cursor data) { Log.i("MyLoader", "===deliverResult"); super.deliverResult(data); adapter.swapCursor(data); } } }

Android Loader异步装载的更多相关文章

  1. [Android] Android 用于异步加载 ContentProvider 中的内容的机制 -- Loader 机制 (LoaderManager + CursorLoader + LoaderManager.LoaderCallbacks)

    Android 用于异步加载 ContentProvider 中的内容的机制 -- Loader 机制 (LoaderManager + CursorLoader + LoaderManager.Lo ...

  2. Android Loader详解

    装载器从android3.0开始引进.它使得在activity或fragment中异步加载数据变得简单.装载器具有如下特性: 它们对每个Activity和Fragment都有效. 他们提供了异步加载数 ...

  3. Android loader 详解

    装载器从android3.0开始引进.它使得在activity或fragment中异步加载数据变得简单.装载器具有如下特性: 它们对每个Activity和Fragment都有效. 他们提供了异步加载数 ...

  4. Android Loader详解一:概述

    装载器从android3.0开始引进.它使得在activity或fragment中异步加载数据变得简单.装载器具有如下特性: 它们对每个Activity和Fragment都有效. 他们提供了异步加载数 ...

  5. ArcGIS Runtime for Android 使用异步GP服务绘制等值线

    关于基于Android上ArcGIS Server GP服务的调用,已经有前辈给出了很好的例子: http://blog.csdn.net/esrichinacd/article/details/92 ...

  6. Android 图片异步加载的体会,SoftReference已经不再适用

      在网络上搜索Android图片异步加载的相关文章,目前大部分提到的解决方案,都是采用Map<String, SoftReference<Drawable>>  这样软引用的 ...

  7. Android图片异步加载之Android-Universal-Image-Loader

    将近一个月没有更新博客了,由于这段时间以来准备毕业论文等各种事务缠身,一直没有时间和精力沉下来继续学习和整理一些东西.最近刚刚恢复到正轨,正好这两天看了下Android上关于图片异步加载的开源项目,就 ...

  8. Android图片异步加载之Android-Universal-Image-Loader(转)

    今天要介绍的是Github上一个使用非常广泛的图片异步加载库Android-Universal-Image-Loader,该项目的功能十分强大,可以说是我见过的目前功能最全.性能最优的图片异步加载解决 ...

  9. (转)ArcGIS Runtime for Android 使用异步GP服务绘制等值线

    关于基于Android上ArcGIS Server GP服务的调用,已经有前辈给出了很好的例子: http://blog.csdn.net/esrichinacd/article/details/92 ...

随机推荐

  1. 详细剖析Spring Cloud 和Spring Cloud Alibaba的前世今生

    我们知道spring cloud可以用来开发微服务,但是应该很少有人真正知道Spring Cloud是什么. 官方的解释是:spring cloud提供了一些可以让开发者快速构建分布式应用的工具,这些 ...

  2. 蓝图before request

    方法1 @bp.before_request def test(): print("test") 方法2 def bp_before_request(): print(test) ...

  3. VMware Workstation 无法连接到虚拟机。请确保您有权运行该程序、访问该程序使用的所有目录以及访问所有临时文件目录。 VMware Authorization Service 当前未运行

    VMware Workstation 无法连接到虚拟机.请确保您有权运行该程序.访问该程序使用的所有目录以及访问所有临时文件目录. VMware Authorization Service 当前未运行 ...

  4. java自定义序列化

    自定义序列化 1.问题引出 在某些情况下,我们可能不想对于一个对象的所有field进行序列化,例如我们银行信息中的设计账户信息的field,我们不需要进行序列化,或者有些field本省就没有实现Ser ...

  5. [cf1083F]The Fair Nut and Amusing Xor

    令$c_{i}=a_{i}\oplus b_{i}$,那么也就是要对$c_{i}$执行操作使其变为0 显然有一个贪心的策略,即从左往右,若当前$c_{i}\ne 0$,则执行对$[i,i+k)$异或$ ...

  6. [luogu4466]和与积

    令$d=\gcd(i,j)$,$i'=\frac{i}{d}$,$j'=\frac{j}{d}$,则$(i',j')=1$,可得$(i'+j',i'j')=1$(假设有公因子$p$,必然有$p|i'或 ...

  7. mybatis新增账号并且返回主键id

    <!--新增账号和权限的关联关系--><insert id="save" useGeneratedKeys="true" keyPropert ...

  8. 一类利用队列优化的DP

    I.导入: 这是一个\(O(n^2)\)的状态和转移方程: \[f(i,j)=\left\{ \begin{aligned} f(i-1,j-1)+k \ (1\leq j)\\ \max_{k \i ...

  9. IDEA 配置背景颜色(豆沙绿)

    1. 定义方案名字(my color) Ctrl + Shift + a --> Color Scheme // 快捷定位配置 // 路径:File --> Settings --> ...

  10. IDEA 注释模板配置

    配置创建类的注释模板 Ctrl + Shift + a --> File and Code Templates // 快捷定位配置 // 路径:File --> Settings --&g ...