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);
            }
        }
    }
}

  

时间: 2024-10-17 04:47:49

LoaderManager与CursorLoader用法的相关文章

Android的CursorLoader用法小结

工作内容集中到Contact模块,这个应用查询数据的地方很多,其使用了CursorLoader这个工具大大简化了代码复杂度.Android自3.0提供了Loader机制,当时google的API只是简单的介绍了一下没有给出用法,大家很少有关注.后来因为重度模型下的性能优化,R&D的朋友发现这个东西非常给力,这才开始注意到这个强大的工具.CursorLoader是Loader的子类,可以说是Loader的升级版.这篇小结以loader为基础说明,弄懂原理之后也就明白了CursorLoader. 先

LoaderManager和Loader初步使用

Android 3.0中提供了一个新概念Loaders,这两天看了之前Contacts的源码,其中自己写了通话记录部分,发现源码里面有很多LoaderManager的使用,现在做一个总结,记录一下LoaderManager的基本用法: 这个其实是分为两部分:LoaderManager和自定义Loader,比如像加载联系人,短信这些系统提供ContentProvider的数据时,其实就是返回一个标准cursor,那我们就没必要自定义loader  直接用loaderManager来管理这个Curs

Android中Loader及LoaderManager的使用(附源码下载)

managedQuery方法的缺陷 Loader是用来更好地加载数据的,在我们谈论Loader之前,我们先研究一下Activity的managedQuery方法,该方法也是用于在Activity中加载数据的.在Android 3.0之前的版本中,我们如果想在Activity中通过ContentResolver对ContentProvider进行查询,我们可以方便的调用Activity的managedQuery方法,该方法的源码如下: @Deprecated public final Cursor

RecyclerView使用详解(三)

在上一篇(RecyclerView使用详解(二))文章中介绍了RecyclerView的多Item布局实现,接下来要来讲讲RecyclerView的Cursor实现,相较于之前的实现,Cursor有更多的使用场景,也更加的常用,特别是配合LoaderManager和CursorLoader进行数据的缓存及加载显示,基于此我们来重点看看RecyclerView的CursorAdapter具体要怎么实现. 一.CursorAdapter实现(配合LoaderManager和CursorLoader)

SQLiteDatabase

一.SQLite: (一).简介: 除了可以使用文件或SharedPreferences存储数据,还可以选择使用SQLite数据库存储数据. 在Android平台上,集成了一个嵌入式关系型数据库--SQLite. SQLite3支持 NULL.INTEGER.REAL(浮点数字).TEXT(字符串文本)和BLOB(二进制对象)等五种数据类型: 虽然它支持的类型只有五种,但实际上sqlite3也接受varchar(n).char(n).decimal(p,s) 等数据类型,只不过在运算或保存时会转

深入源码解析Android中Loader、AsyncTaskLoader、CursorLoader、LoaderManager

如果对Loader.AsyncTaskLoader.CursorLoader.LoaderManager等概念不明白或不知道如何使用Loader机制,可参见博文Android中Loader及LoaderManager的使用(附源码下载).本文主要通过研究Loader及其子类的生命周期的方式来对Loader及其子类.LoaderManager的源码进行研究. Loader是靠LoaderManager管理的,LoaderManager可以同时管理多个Loader,即LoaderManager与Lo

LoaderManager使用详解(二)---了解LoaderManager

了解LoaderManager 这篇文章将介绍LoaderManager类,这是该系列的第二篇文章. 一:Loaders之前世界 二:了解LoaderManager 三:实现Loaders 四:实例:AppListLoader 注意: 要了解这一LoaderManager这部分知识,要求对Loaders如何工作有基本了解.Loaders的实现将在下一篇文章中涵盖.现在你只需要将Loaders看成一个简单.字包含的对象.该对象特性包括:1.在一个单独线程载入数据:2.监测底层数据源,当探测到有改变

LoaderManager使用详解(一)---没有Loader之前的世界

来源: http://www.androiddesignpatterns.com/2012/07/loaders-and-loadermanager-background.html 感谢作者Alex Lockwood的努力,让我们看到如此精彩的文章. 第一部分 没有Loader之前的世界 这一部分将对Loaders和LoaderManager做一个简短的介绍.第一节将在Android3.0之前如何载入数据,指出其缺陷.第二节讲述每个类的目的,以及它们异步载入数据的能力. 这篇文章是有关Loade

使用Loader实时查询本地数据库用法

在看Android的文档时,看到了这么一个东西: Loader 究竟是什么东西呢? Introduced in Android 3.0, loaders make it easy to asynchronously load data in an activity or fragment. Loaders have these characteristics: 1.They are available to every Activity and Fragment.  //支持Activity和F