Android 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()方法有以下参数:
- 一个唯一ID来标识装载器
- 可选的参数,用于装载器初始化
- 一个LoaderManager.LoaderCallbacks的实现。被LoaderManager调用以报告装载器的事件。一般窗体都实现了这个接口,所以传的是它自己:this;
- initLoader()保证一个装载器被初始化并激活.它具有两种可能的结果:
- 如果Id所指的装载器已经存在,那么这个装载器将被重用
- 如果装载器不存在,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()才能依次调用下一个即将执行的方法
- 在loadInBackground()方法中执行数据库查询,返回Cursor;
- 在deliverResult()方法中执行跟适配器交换数据的操作。adapter.swapCursor(data)。
- Flags used to determine the behavior of the adapter; may be any combination of
FLAG_AUTO_REQUERYandFLAG_REGISTER_CONTENT_OBSERVER。 - FLAG_AUTO_REQUERY(常量值:1 )从 API11 开始已经废弃。因为他会在应用程序的 UI 线程中执行游标查询操作, 导致响应缓慢甚至应用程序无响应(ANR)的错误。作为替代方案,请使用 LoaderManager 和 AsyncTaskLoader、CursorLoader。
- 如果设置FLAG_REGISTER_CONTENT_OBSERVER(常量值:2),适配器会在Cursor上注册一个内容观测器,当通知到达时会调用 onContentChanged() 方法。
当一个已创建的装载器被重置从而使其数据无效时,此方法被调用.此回调使你能发现什么时候数据将被释放。你可以释放对它的引用。
(四)、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异步装载的更多相关文章
- [Android] Android 用于异步加载 ContentProvider 中的内容的机制 -- Loader 机制 (LoaderManager + CursorLoader + LoaderManager.LoaderCallbacks)
Android 用于异步加载 ContentProvider 中的内容的机制 -- Loader 机制 (LoaderManager + CursorLoader + LoaderManager.Lo ...
- Android Loader详解
装载器从android3.0开始引进.它使得在activity或fragment中异步加载数据变得简单.装载器具有如下特性: 它们对每个Activity和Fragment都有效. 他们提供了异步加载数 ...
- Android loader 详解
装载器从android3.0开始引进.它使得在activity或fragment中异步加载数据变得简单.装载器具有如下特性: 它们对每个Activity和Fragment都有效. 他们提供了异步加载数 ...
- Android Loader详解一:概述
装载器从android3.0开始引进.它使得在activity或fragment中异步加载数据变得简单.装载器具有如下特性: 它们对每个Activity和Fragment都有效. 他们提供了异步加载数 ...
- ArcGIS Runtime for Android 使用异步GP服务绘制等值线
关于基于Android上ArcGIS Server GP服务的调用,已经有前辈给出了很好的例子: http://blog.csdn.net/esrichinacd/article/details/92 ...
- Android 图片异步加载的体会,SoftReference已经不再适用
在网络上搜索Android图片异步加载的相关文章,目前大部分提到的解决方案,都是采用Map<String, SoftReference<Drawable>> 这样软引用的 ...
- Android图片异步加载之Android-Universal-Image-Loader
将近一个月没有更新博客了,由于这段时间以来准备毕业论文等各种事务缠身,一直没有时间和精力沉下来继续学习和整理一些东西.最近刚刚恢复到正轨,正好这两天看了下Android上关于图片异步加载的开源项目,就 ...
- Android图片异步加载之Android-Universal-Image-Loader(转)
今天要介绍的是Github上一个使用非常广泛的图片异步加载库Android-Universal-Image-Loader,该项目的功能十分强大,可以说是我见过的目前功能最全.性能最优的图片异步加载解决 ...
- (转)ArcGIS Runtime for Android 使用异步GP服务绘制等值线
关于基于Android上ArcGIS Server GP服务的调用,已经有前辈给出了很好的例子: http://blog.csdn.net/esrichinacd/article/details/92 ...
随机推荐
- linux初中级命令语言
Linux:开源免费.大部分软件都可以自由获取,同样功能的软件选择较少.主要是字符模式,命令行界面且发行版本较多,难以集中攻击. Xshell与xftp是什么? xshell是一个客户端软件,我们本地 ...
- go的变量、常量以及判断变量的数据类型
1.定义变量 p.p1 { margin: 0; font: 12px "Helvetica Neue"; color: rgba(69, 69, 69, 1) } span.s1 ...
- 一、Windows部署RabbitMQ
RabbitMQ官方网站非常详细,以下只是本人学习过程的整理 一.Windows部署RabbitMQ:https://www.cnblogs.com/yangleiyu/p/15539618.html ...
- 1个月连载30个设计模式真实案例(附源码),挑战年薪60W不是梦
本文所有内容均节选自<设计模式就该这样学> 本文自2012年10月29日起持续连载,请大家持续关注.... 序言 Design Patterns: Elements of Reusable ...
- mac下将python2.7改为python3
mac下将python2.7改为python3 查看当前电脑python版本 python -V 修改.bash_profile文件 vi ~/.bash_profile //编辑bash_profi ...
- Effective C++ 总结笔记(二)
二.构造/析构/赋值运算 05.了解C++默默编写并调用那些函数 如果自己不声明, 编译器就会暗自为class创建一个default构造函数.一个copy构造函数.一个copy assignment操 ...
- ELK 7.4.2 单机安装配置
Java环境准备 JDK下载 https://www.oracle.com/technetwork/java/javase/overview/index.html [root@manager ~]# ...
- [loj6736]最小连通块
定义$f(S)$表示点集$S$的最小连通块 做法1 通过对所有节点判定,可以在$n$次询问中求出具体的$f(S)$ 对于$x\ne y$,显然$(x,y)\in E$当且仅当$f(\{x,y\})=\ ...
- mybatis源码分析二
这次分析mybatis的xml文件 1. <?xml version="1.0" encoding="UTF-8" ?> <configura ...
- 深入理解Redis 数据结构—双链表
在 Redis 数据类型中的列表list,对数据的添加和删除常用的命令有 lpush,rpush,lpop,rpop,其中 l 表示在左侧,r 表示在右侧,可以在左右两侧做添加和删除操作,说明这是一个 ...