一.基本概念
 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);
}
}
}
}

Android LoaderManager与CursorLoader用法的更多相关文章

  1. LoaderManager与CursorLoader用法

    一.基本概念 1.LoaderManager LoaderManager用来负责管理与Activity或者Fragment联系起来的一个或多个Loaders对象. 每个Activity或者Fragme ...

  2. android的logcat详细用法

    Android日志系统提供了记录和查看系统调试信息的功能.日志都是从各种软件和一些系统的缓冲区中记录下来的,缓冲区可以通过 logcat 命 令来查看和使用. 使用logcat命令 你可以用 logc ...

  3. 怎么通过activity里面的一个按钮跳转到另一个fragment(android FragmentTransaction.replace的用法介绍)

    即:android FragmentTransaction.replace的用法介绍 Fragment的生命周期和它的宿主Activity密切相关,几乎和宿主Activity的生命周期一致,他们之间最 ...

  4. Android开发中Bundle用法包裹数据(转)

    Android开发中Bundle用法包裹数据 Bundle的经典用法,包裹数据放入Intent中,目的在于传输数据. SDK 里是这样描述: A mapping from String values ...

  5. 【转】Android各种Adapter的用法

    转自:http://my.oschina.net/u/658933/blog/372151 Android各种Adapter的用法 发表于5个月前(2015-01-27 10:56)   阅读(143 ...

  6. android application类的用法

    android application类的用法 Application是android系统Framework提供的一个组件,它是单例模式(singleton),即每个应用只有一个实例,用来存储系统的一 ...

  7. android 中uri.parse()用法

    android 中uri.parse()用法 1,调web浏览器 Uri myBlogUri = Uri.parse("http://xxxxx.com"); returnIt = ...

  8. Android webView 正确的用法

    Android webView 正确的用法 引言: 我在网络找了几个例子,基本上都有问题,<Android疯狂讲义>13.4中的源代码也有问题.终于在官网找到正确的用法.点我. 基本用法: ...

  9. Android RxJava 2 的用法 just 、from、map、subscribe、flatmap、Flowable、Function、Consumer ...【转】

    先简单说说RxJava的用途与价值 原文出处:Android RxJava 2 的用法 用途: 异步 (也就是开线程跳转) 价值: 面对复杂的逻辑,它依然 简洁 ,代码 易读 RxJava2 与 Rx ...

随机推荐

  1. 3.Maven之(三)Maven插件

    转自:https://yq.aliyun.com/ziliao/312162 Maven本质上是一个插件框架,它的核心并不执行任何具体的构建任务,所有这些任务都交给插件来完成,像编译是通过maven- ...

  2. 将BT下载对抗到底

    将BT下载对抗到底      随着互联网业务的多元化,各种P2P应用也越来越多,在企业中多数流量都会被类似于BT的下载所占用,BT之所以会危害到局域网,是因为它占用了大量网络带宽.网络管理员可以通过一 ...

  3. ASP.NET MVC Web API 学习笔记---第一个Web API程序---近来很多大型的平台都公开了Web API

    1. Web API简单说明 近来很多大型的平台都公开了Web API.比如百度地图 Web API,做过地图相关的人都熟悉.公开服务这种方式可以使它易于与各种各样的设备和客户端平台集成功能,以及通过 ...

  4. centos的dns配置总结

    找的一篇好的存根 DNS正反向解析 DNS(Domain Name Service)域名服务.就是域名解析服务器.所谓名称解析的过程就是某个应用程序基于某个搜索键在指定的数据库中查询.而后查询到某些对 ...

  5. arping---发送arp请求到一个相邻主机

    arping命令是用于发送arp请求到一个相邻主机的工具,arping使用arp数据包,通过ping命令检查设备上的硬件地址.能够测试一个ip地址是否是在网络上已经被使用,并能够获取更多设备信息.功能 ...

  6. 使用pandas导出PostgreSQL 模式下的所有表数据并保存

    PostgreSQL PostgreSQL 是一个非常强大的数据库,它是一个免费的对象-关系数据库服务器(数据库管理系统).PostgreSQL支持大部分 SQL 标准, 在语句上也有很大的相似的地方 ...

  7. ZOJ Problem Set - 3819Average Score

    ZOJ Problem Set - 3819Average Score 题目链接 题目大意:给你两个班的的学生的分数(A,B班).A班有一个学生的分数没有给出. 如今要求你给出这个学生分数的上下限.使 ...

  8. 在OSG 实现的 oculus rift 效果

    在OSG 实现的oculus rift 效果,还不错 这个是Delta3d中实现的 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemh1eWluZ3Fpb ...

  9. LinearLayout-margin不起作用的处理

    1.如果LinearLayout中使用android:layout_marginRight不起作用,通过测试原来在android2.x中,如果一个控件中有android:layout_gravity属 ...

  10. ListView- 最后一行添加控件

    今天在做一个功能的时候,要求必须是在一个listview下,有一段提示行的文字,自己的那个listview的adapter用的是cursoradapter,这样的话,处理布局的灵活性就大打折扣了.最开 ...