Loader详解

1.装载器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来执行一个被管理的查询就不行了。

2.使用加载器

一个使用装载器的应用会典型的包含如下组件:

  • 一个Activity或Fragment.
  • 一个LoaderManager的实例.
  • 一个加载被ContentProvider所支持的数据的CursorLoader.或者,你可以从Loader或AsyncTaskLoader实现你自己的装载器来从其它源加载数据.
  • 一个LoaderManager.LoaderCallbacks的实现.这是你创建新的装载器以及管理你的已有装载器的引用的地方.
  • 一个显示装载器的数据的途径,例如使用一个SimpleCursorAdapter.
  • 一个数据源,比如当是用CursorLoader时,它将是一个ContentProvider

启动一个装载器

LoaderManager管理一个Activiry或Fragment中的一个或多个装载器.但每个activity或fragment只拥有一个LoaderManager.

你通常要在activity的onCreate()方法中或fragment的onActivityCreated()方法中初始化一个装载器.你可以如下创建

// 准备装载器.可以重连一个已经存在的也可以启动一个新的.  
getLoaderManager().initLoader(0,null, this);  

initLoader()方法有以下参数:

  • 一个唯一ID来标志装载器.在这个例子中,ID是0.
  • 可选的参数,用于装载器初始化时(本例中是null).
  • 一个LoaderManager.LoaderCallbacks的实现.被LoaderManager调用以报告装载器的事件,在这个例子中,类本实现了这个接口,所以传的是它自己:this.

initLoader()保证一个装载器被初始化并激活.它具有两种可能的结果:

  • 如果ID所指的装载器已经存在,那么这个装载器将被重用.
  • 如果装载器不存在,initLoader()就触发LoaderManager.LoaderCallbacks的方法onCreateLoader().这是你实例化并返回一个新装载器的地方.

在这两种情况中,传入的LoaderManager.LoaderCallbacks的实现都与装载器绑定在一起.并且会在装载器状态变化时被调用.如果在调用这个方法时,调用者正处于启动状态,并且所请求的装载器已存在并产生了数据,那么系统会马上调用onLoadFinished()(也就是说在initLoader()还在执行时).所以你必须为这种情况的发生做好准备.

注意initLoader()返回所创建的装载器,但是你不需保存一个对它的引用.LoaderManager自动管理装载器的生命.LoaderManager会在需要时开始和停止装载动作,并且维护装载器的状态和它所关联的内容.这意味着,你很少与装载器直接交互.你通常都是使用LoaderManager.LoaderCallbacks的方法们在某个事件发生时介入到数据加载的过程中.

  

3.回调及完整例子

onLoadFinished

这个方法是在前面已创建的装载器已经完成其加载过程后被调用.这个方法保证会在应用到装载器上的数据被释放之前被调用.在此方法中,你必须删除所有对旧数据的使用(因为它将很快会被删除),但是不要自己去释放它们,因为它们的装载器会做这些事情.

装载器一旦了解到应用不再使用数据时,将马上释放这些数据.例如,如果数据是一个从CursorLoader来的游标,你不应调用游标的close().如果游标被放置在一个CursorAdapter中,你应使用swapCursor()方法,以使旧的游标不被关闭.例如:

//这个Adapter被用于显示列表的数据.  
SimpleCursorAdapter mAdapter;  
...  
  
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {  
    // Swap the new cursor in.  (The framework will take care of closing the  
    // old cursor once we return.)  
    mAdapter.swapCursor(data);  
}  

onLoaderReset

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

下面这个实现调用参数为null的swapCursor():

// 这个Adapter被用于显示列表的数据.  
SimpleCursorAdapter mAdapter;  
...  
  
public void onLoaderReset(Loader<Cursor> loader) {  
    //此处是用于上面的onLoadFinished()的游标将被关闭时执行, 我们需确保我们不再使用它.  
    mAdapter.swapCursor(null);  
}  

例子
作为一个例子,这里完整实现了一个Fragment显示一个包含从联系人contentprovider 返回查询数据的ListView的内容的功能.它使用一个CursorLoader来管理对provider的查询.

public static class CursorLoaderListFragment extends ListFragment  
        implements OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> {  
  
    // 这是用于显示列表数据的Adapter  
    SimpleCursorAdapter mAdapter;  
  
    // 如果非null,这是当前的搜索过虑器  
    String mCurFilter;  
  
    @Override public void onActivityCreated(Bundle savedInstanceState) {  
        super.onActivityCreated(savedInstanceState);  
  
        // 如果列表中没有数据,就给控件一些文字去显示.在一个真正的应用  
        // 中这应用资源中取得.  
        setEmptyText("No phone numbers");  
  
        // 我们在动作栏中有一个菜单项.  
        setHasOptionsMenu(true);  
  
        // 创建一个空的adapter,我们将用它显示加载后的数据  
        mAdapter = new SimpleCursorAdapter(getActivity(),  
                android.R.layout.simple_list_item_2, null,  
                new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS },  
                new int[] { android.R.id.text1, android.R.id.text2 }, 0);  
        setListAdapter(mAdapter);  
  
        // 准备loader.可能是重连到一个已存在的或开始一个新的  
        getLoaderManager().initLoader(0, null, this);  
    }  
  
    @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {  
        // 放置一个动作栏项用于搜索.  
        MenuItem item = menu.add("Search");  
        item.setIcon(android.R.drawable.ic_menu_search);  
        item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);  
        SearchView sv = new SearchView(getActivity());  
        sv.setOnQueryTextListener(this);  
        item.setActionView(sv);  
    }  
  
    public boolean onQueryTextChange(String newText) {  
        // 在动作栏上的搜索字串改变时被调用.更新  
        //搜索过滤器,并重启loader来执行一个新的查询  
        mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;  
        getLoaderManager().restartLoader(0, null, this);  
        return true;  
    }  
  
    @Override public boolean onQueryTextSubmit(String query) {  
        // 我们不关心这个方法  
        return true;  
    }  
  
    @Override public void onListItemClick(ListView l, View v, int position, long id) {  
        // 写入你想写的代码  
        Log.i("FragmentComplexList", "Item clicked: " + id);  
    }  
  
    // 这是我们想获取的联系人中一行的数据.  
    static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {  
        Contacts._ID,  
        Contacts.DISPLAY_NAME,  
        Contacts.CONTACT_STATUS,  
        Contacts.CONTACT_PRESENCE,  
        Contacts.PHOTO_ID,  
        Contacts.LOOKUP_KEY,  
    };  
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {  
        // 当一个新的loader需被创建时调用.本例仅有一个Loader,  
        //所以我们不需关心ID.首先设置base URI,URI指向的是联系人  
        Uri baseUri;  
        if (mCurFilter != null) {  
            baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,  
                    Uri.encode(mCurFilter));  
        } else {  
            baseUri = Contacts.CONTENT_URI;  
        }  
  
        // 现在创建并返回一个CursorLoader,它将负责创建一个  
        // Cursor用于显示数据  
        String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND ("  
                + Contacts.HAS_PHONE_NUMBER + "=1) AND ("  
                + Contacts.DISPLAY_NAME + " != ‘‘ ))";  
        return new CursorLoader(getActivity(), baseUri,  
                CONTACTS_SUMMARY_PROJECTION, select, null,  
                Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");  
    }  
  
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {  
        // 将新的cursor换进来.(框架将在我们返回时关心一下旧cursor的关闭)  
        mAdapter.swapCursor(data);  
    }  
  
    public void onLoaderReset(Loader<Cursor> loader) {  
        //在最后一个Cursor准备进入上面的onLoadFinished()之前.  
        // Cursor要被关闭了,我们需要确保不再使用它.  
        mAdapter.swapCursor(null);  
    }  
}  

  

  

  

时间: 2024-10-12 20:52:01

Loader详解的相关文章

Android Loader详解(官方文档翻译)

装载器从android3.0开始引进.它使得在activity或fragment中异步加载数据变得简单.装载器具有如下特性: 它们对每个Activity和Fragment都有效. 他们提供了异步加载数据的能力. 它们监视数据源的一将一动并在内容改变时传送新的结果. 当由于配置改变而被重新创建后,它们自动重连到上一个加载器的游标,所以不必重新查询数据. 装载器API概述 在使用装载器时,会涉及很多类和接口们,我们在下表中对它们总结一下: Class/Interface 说明 LoaderManag

Android loader 详解

装载器从android3.0开始引进.它使得在activity或fragment中异步加载数据变得简单.装载器具有如下特性: 它们对每个Activity和Fragment都有效. 他们提供了异步加载数据的能力. 它们监视数据源的一将一动并在内容改变时传送新的结果. 当由于配置改变而被重新创建后,它们自动重连到上一个加载器的游标,所以不必重新查询数据. 装载器API概述 在使用装载器时,会涉及很多类和接口们,我们在下表中对它们总结一下: Class/Interface 说明 LoaderManag

Android Loader详解

一,android装载器基本方法 装载器从android3.0开始引进.它使得在activity或fragment中异步加载数据变得简单.装载器具有如下特性: 它们对每个Activity和Fragment都有效. 他们提供了异步加载数据的能力. 它们监视数据源的一将一动并在内容改变时传送新的结果. 当由于配置改变而被重新创建后,它们自动重连到上一个加载器的游标,所以不必重新查询数据. 装载器API概述 在使用装载器时,会涉及很多类和接口们,我们在下表中对它们总结一下: Class/Interfa

SQL*Loader 详解

在 Oracle 数据库中,我们通常在不同数据库的表间记录进行复制或迁移时会用以下几种方法: 1. A 表的记录导出为一条条分号隔开的 insert 语句,然后执行插入到 B 表中2. 建立数据库间的 dblink,然后用 create table B as select * from [email protected] where ...,或 insert into B select * from [email protected] where ...3. exp A 表,再 imp 到 B

PHP源代码加密软件工具zend guard 使用教程及免费下载功能详解loader 安装破解

原文来自龙博方案网http://www.fanganwang.com/product/1368 Zend Guard?,以前称为的 Zend 编码器,从逆向工程,未经许可定制,无牌使用和再分配方面保护您的商业 PHP 4和 PHP 5应用. Zend Guard?,倾向前身 Zend 编码器,许独立软件供应商(ISVs)和 IT 经理们安全地和自信地分配和管理他们的 PHP 应用的开发,同时己的源代码. Zend Guard? 不仅能编码你们应用软件的源代码,而且还通过不同的应用组件名称的困惑来

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

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

【译】UNIVERSAL IMAGE LOADER. PART 3(四个DisplayImage重载方法详解)

在之前的文章,我们重点讲了Android-Universal-Image-Loader的三个主要组件,现在我们终于可以开始使用它了. Android-Universal-Image-Loader有四个重载方法 void displayImage(String url, ImageView view) void displayImage(String url, ImageView view, DisplayImageOptions options) void displayImage(String

【译】UNIVERSAL IMAGE LOADER.PART 2---ImageLoaderConfiguration详解

ImageLoader类中包含了所有操作.他是一个单例,为了获取它的一个单一实例,你需要调用getInstance()方法.在使用ImageLoader来显示图片之前,你需要初始化它的配置-ImageLoaderConfiguration使用init(…)方法.然后,你就可以使用可以明确地根据需要使用不同形式的displayImage(…). 总之,ImageLoader最简单的用法如下所示(使用默认配置): ImageView imageView = ... // view, where th

详解 linux中的grub

grub是什么: grub是引导操作系统的程序,它会根据自己的配置文件,去引导内核,当内核被加载到内存以后, 内核会根据grub配置文件中的配置,找到根分区所使用的文件系统对应的驱动,通过根分区文件系统 对应的驱动,挂载根分区,从而达到启动操作系统的目的. 在了解grub以前,请先大体上了解一下centos5/6的启动过程,然后再理解grub就更容易了, 还记的我们以前总结过的centos5系统启动流程吗,如下图,此处我们重点讨论下图红框中的步骤. centos5/6中使用grub作为bootl