LoaderManager与CursorLoader用法
一.基本概念
1.LoaderManager
LoaderManager用来负责管理与Activity或者Fragment联系起来的一个或多个Loaders对象.
每个Activity或者Fragment都有唯一的一个LoaderManager实例(通过getLoaderManager()方法获得),用来启动,停止,保持,重启,关闭它的Loaders,这些功能可通过调用initLoader()/restartLoader()/destroyLoader()方法来实现.
LoaderManager并不知道数据如何装载以及何时需要装载.相反,它只需要控制它的Loaders们开始,停止,重置他们的Load行为,在配置变换或数据变化时保持loaders们的状态,并使用接口来返回load的结果.
2.Loader
Loades负责在一个单独线程中执行查询,监控数据源改变,当探测到改变时将查询到的结果集发送到注册的监听器上.Loader是一个强大的工具,具有如下特点
(1)它封装了实际的数据载入.
Activity或Fragment不再需要知道如何载入数据.它们将该任务委托给了Loader,Loader在后台执行查询要求并且将结果返回给Activity或Fragment.
(2)客户端不需要知道查询如何执行.Activity或Fragment不需要担心查询如何在独立的线程中执行,Loder会自动执行这些查询操作.
这种方式不仅减少了代码复杂度同事也消除了线程相关bug的潜在可能.
(3)它是一种安全的事件驱动方式.
Loader检测底层数据,当检测到改变时,自动执行并载入最新数据.
这使得使用Loader变得容易,客户端可以相信Loader将会自己自动更新它的数据.
Activity或Fragment所需要做的就是初始化Loader,并且对任何反馈回来的数据进行响应.除此之外,所有其他的事情都由Loader来解决.
二.异步Loader的实现原理
(1)执行异步载入的任务.为了确保在一个独立线程中执行载入操作,Loader的子类必须继承AsyncTaskLoader<D>而不是Loader<D>类.
AsyncTaskLoader<D>是一个抽象Loader,它提供了一个AsyncTask来做它的执行操作.
当定义子类时,通过实现抽象方法loadInBackground方法来实现异步task.该方法将在一个工作线程中执行数据加载操作.
(2)在一个注册监听器中接收载入完成返回的结果.
对于每个Loader来说,LoaderManager注册一个OnLoadCompleteListener<D>,该对象将通过调用onLoadFinished(Loader<D> loader, D result)方法使Loader将结果传送给客户端.
Loader通过调用Loader#deliverResult(D result),将结果传递给已注册的监听器.
三.Loader三种不同状态.
已启动: 处于已启动状态的Loader会执行载入操作,并在任何时间将结果传递到监听器中.已启动的Loader将会监听数据改变,当检测到改变时执行新的载入.
一旦启动,Loader将一直处在已启动状态,一直到转换到已停止和重置,这是唯一一种onLoadFinished永远都会调用的状态。
已停止: 处于已停止状态的Loader将会继续监听数据改变,但是不会将结果返回给客户端.在已停止状态,Loader可能被启动或者重启.
重置: 当Loader处于重置状态时,将不会执行新的载入操作,也不会发送新的结果,也不会检测数据变化.
当一个Loader进入重置状态,它必须解除对应的数据引用,方便垃圾回收(客户端也必须确定,在Loader无效之后,移除了所有对该数据的引用).
通常,重置Loader不会两次调用.然而,在某些情况下他们可能会启动,所以如果必要的话,它们必须能够适时重置.
四.接收Loader数据改变的通知.
必须有一个观察者接受数据源改变的通知.
Loader必须实现这些Observer其中之一(ContentObserver,BroadcastReceiver等),来检测底层数据源的改变.
当检测到数据改变,观察者必须调用Loader#onContentChanged().在该方法中执行两种不同操作:
(1)如果Loader已经处于启动状态,就会执行一个新的载入操作;
(2)设置一个flag标识数据源有改变,这样当Loader再次启动时,就知道应该重新载入数据了.
五.CursorLoader实现LoaderManager.LoaderCallbacks接口方法.接口声明及使用如下:
public interface LoaderCallbacks<D> {
public Loader<D> onCreateLoader(int id, Bundle args);
public void onLoadFinished(Loader<D> loader, D data);
public void onLoaderReset(Loader<D> loader);
}
onCreateLoader方法将在创建Loader时候调用,此时需要提供查询的配置,如监听一个URI.
这个方法会在loader初始化的时调用,即调用下面的代码时调用:
getLoaderManager().initLoader(id, bundle, loaderCallbacks);
initLoader函数原型为:
<D> Loader<D> android.app.LoaderManager.initLoader(int id, Bundle bundle, LoaderCallbacks<D> loaderCallbacks);
第1个参数loader的ID,可自定义一个常量值,便于实现多个Loader;
第2个参数一般置null;
第3个参数是实现了LoaderManager.LoaderCallbacks实现类对象.
onLoadFinished方法,在Loader完成任务后调用,一般在此读取结果.
onLoaderReset方法是在配置发生变化时调用,一般调用下面的代码后调用:
getLoaderManager().restartLoader(id, bundle, loaderCallbacks);
restartLoader方法参数同initLoader,重新初始化loader之后,需要用来释放对前面loader查询到的结果引用.
六.一个具体监听通话记录的示例
在Activity中onCreate调用
CallLogsLoaderListener callLogsCallback = new CallLogsLoaderListener(this);
getLoaderManager().initLoader(0, null, callLogsCallback);
在onDestroy调用
getLoaderManager().destroyLoader(0);
配置权限
<uses-permission android:name="android.permission.WRITE_CALL_LOG" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
具体的类实现
import android.app.LoaderManager;
import android.content.Context;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.database.CursorWrapper;
import android.os.Bundle;
import android.provider.CallLog;
import android.util.Log; public class CallLogsLoaderListener implements
LoaderManager.LoaderCallbacks<Cursor> { private Context mContext; public CallLogsLoaderListener(Context context) {
mContext = context;
} @Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
CursorLoader loader = new CursorLoader(mContext,
CallLog.Calls.CONTENT_URI, null, null, null, null) {
@Override
public Cursor loadInBackground() {
Cursor cursor = super.loadInBackground();
if (cursor == null)
return null;
CallLogsCursor callLogsCursor = new CallLogsCursor(cursor);
return callLogsCursor;
}
};
return loader;
} @Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
} @Override
public void onLoaderReset(Loader<Cursor> loader) {
} public class CallLogsCursor extends CursorWrapper { public CallLogsCursor(Cursor cursor) {
super(cursor); int nameIndex = cursor.getColumnIndex(CallLog.Calls.CACHED_NAME);
int numberIndex = cursor.getColumnIndex(CallLog.Calls.NUMBER);
int typeIndex = cursor.getColumnIndex(CallLog.Calls.TYPE);
int dateIndex = cursor.getColumnIndex(CallLog.Calls.DATE);
int durationIndex = cursor.getColumnIndex(CallLog.Calls.DURATION); // 从游标的最后索引往前查询,因为最新的通话记录在最后
for (cursor.moveToLast(); !cursor.isBeforeFirst(); cursor
.moveToPrevious()) {
// 姓名
String name = cursor.getString(nameIndex);
// 号码
String number = cursor.getString(numberIndex);
// 类型
int type = cursor.getInt(typeIndex);
// 日期
long date = cursor.getLong(dateIndex);
// 通话时长
int duration = cursor.getInt(durationIndex); Log.d("debug", "name=" + name + ", number=" + number
+ ", type=" + type + ", date=" + date + ", duration="
+ duration);
}
}
}
}
LoaderManager与CursorLoader用法的更多相关文章
- Android LoaderManager与CursorLoader用法
一.基本概念 1.LoaderManager LoaderManager用来负责管理与Activity或者Fragment联系起来的一个或多个Loaders对象. 每个Activity或者Fragme ...
- Android的CursorLoader用法小结
工作内容集中到Contact模块,这个应用查询数据的地方很多,其使用了CursorLoader这个工具大大简化了代码复杂度.Android自3.0提供了Loader机制,当时google的API只是简 ...
- RecyclerView解密篇(三)
在上一篇(RecyclerView使用详解(二))文章中介绍了RecyclerView的多Item布局实现,接下来要来讲讲RecyclerView的Cursor实现,相较于之前的实现,Cursor有更 ...
- Android RecyclerView使用详解(三)
在上一篇(RecyclerView使用详解(二))文章中介绍了RecyclerView的多Item布局实现,接下来要来讲讲RecyclerView的Cursor实现,相较于之前的实现,Cursor有更 ...
- Android列表视图(List View)
Android列表视图(ListView) ListView是一个显示滚动项列表的示视图组(viewgroup),通过使用适配器(Adapter)把这些列表项自动插入到列表中.适配器比如从一个数组或是 ...
- RecyclerView使用技巧(item动画及嵌套高度适配解决方案)
原文地址 · Frank-Zhu http://frank-zhu.github.io/android/2015/02/26/android-recyclerview-part-3/?utm_sou ...
- Loader之一:基本原理
参考APIDEMO及http://developer.android.com/guide/components/loaders.html#app 1.Introduced in Android 3.0 ...
- Loader之一:基本原理 分类: H1_ANDROID 2013-11-16 10:29 1923人阅读 评论(0) 收藏
参考APIDEMO及http://developer.android.com/guide/components/loaders.html#app 1.Introduced in Android 3.0 ...
- [Android] Android 用于异步加载 ContentProvider 中的内容的机制 -- Loader 机制 (LoaderManager + CursorLoader + LoaderManager.LoaderCallbacks)
Android 用于异步加载 ContentProvider 中的内容的机制 -- Loader 机制 (LoaderManager + CursorLoader + LoaderManager.Lo ...
随机推荐
- 一个五位数ABCDE乘以9,得到EDCBA,求此五位数
此题是面试时某面试官突然抛出的,要求逻辑分析推导,不许编码,5分钟时间算出来最终结果,当然,最终没有完全推算出来 下面是编码实现 #一个五位数ABCDE*9=EDCBA,求此数 for a in ra ...
- PAT-甲级解题目录
PAT甲级题目:点这里 pat解题列表 题号 标题 题目类型 10001 1001 A+B Format (20 分) 字符串处理 1003 1003 Emergency (25 分) 最短路径 ...
- Linux error:No space left on device
一台Oracle数据库服务器在关机重启后,Oracle监听无法启动,提示错误 Linux error:no space left on device 提示可知:问题是出在磁盘空间不足 但是初步查看分区 ...
- mysql唯一查询
MySQL单一字段唯一其他字段差异性忽略查询.在使用MySQL时,有时需要查询出某个字段不重复的记录,虽然mysql提供 有distinct这个关键字来过滤掉多余的重复记录只保留一条,但往往只用它来返 ...
- Calculator 2
github地址:https://github.com/YooRarely/object-oriented.git 新增: 计算类(拥有计算功能) 采用符号优先级计算方法 对符号不匹配的如 -2 ,自 ...
- LintCode-165.合并两个排序链表
合并两个排序链表 将两个排序链表合并为一个新的排序链表 样例 给出 1->3->8->11->15->null,2->null, 返回 1->2->3- ...
- TCP系列20—重传—10、早期重传(ER)
一.介绍 在前面介绍thin stream时候我们介绍过有两种场景下可能不会产生足够的dup ACK来触发快速重传,一种是游戏类响应交互式tcp传输,另外一种是传输受到拥塞控制的限制,只能发送少量TC ...
- C# 执行bat文件
private void RunBat(string batPath) { Process pro = new Process(); FileInfo file = new FileInfo(batP ...
- BAT批处理(六)
字符串处理 批处理有着具有非常强大的字符串处理能力,其功能绝不低于C语言里面的字符串函数集.批处理中可实现的字符串处理功能有:截取字符串内容.替换字符串特定字段.合并字符串.扩充字符串等功能.下面对这 ...
- tab键、快捷键、默认按钮、小数点输入的使用--四则运算
1. 窗体Tab键的顺序设置 选中窗体-视图-tab键顺序 label不适用tab键 2. 热键设置和快捷键设置 热键:无论光标在哪都可以 快捷键:出现界面后才能按 添加label 更改label的T ...