- 什么是Loader
Loader从android3.0开始引进。它使得在activity或fragment中异步加载数据变得简单。装载器具有如下特性:
1、 它们对每个Activity和Fragment都有效。
2、他们提供了异步加载数据的能力。
3、 它们监视数据源的一举一动并在内容改变时及时通知客户端。
4、当由于配置改变而被重新创建后,它们自动重连到上一个加载器的游标,所以不必重新查询数据。
Loader的数据源可以是磁盘、数据库、ContentProvider、网络或者另一个进程。
Loader可以在不阻塞主线程的情况下获取并发送结果数据给接受者。(异步)
Loader有三种内置类型:Loader、AsyncTaskLoader和CursorLoader。
Loader [startLoading() stopLoading]
AsyncTackLoading<D>[D laodInBackground]继承Loader
CursorLoader[setUri(uri) setSelection(String)]继承AsyncTackLoading
- Loader作为基类,本身并没多大用处,他仅仅定义了供LoaderManager与其他Loader通讯时使用的API。
- AsyncTaskLoader也是一个抽象的Loader。他使用AsyncTask将数据加载任务转移到其他线程上处理。几乎我们创建的有用的Loader类都是AsyncTaskLoader的子类。
- CursorLoader是AsyncTaskLoader的一个子类,它借助ContentResolver从ContentProvider加载Cursor。
LoaderManager、LoaderManager. LoaderCallbacks、Loader
- Loader API概述
-
Class/Interface
Description
LoaderManager
和Activity和Fragment有关的抽象类,可以用来管理一个或者多个Loader实例。这可以帮助一个应用程序管理长时间运行的方法和 Activity或者Fragment的生命周期结合起来。最常用的是一个CursorLoader,对于加载其他类型的数据来写入自己的装载机,应用程 序都是免费的。 每个activity或者fragment只能有一个LoaderManager.但是一个LoaderManager可以有多个Loaders。
LoaderManager.LoaderCallbacks
客户端和LoaderManager交互的回调接口。例如:你使用onCreateLoader()回调方法来创建一个新的Loader。
Loader
执行异步加载数据的的抽象类。是loader的父类。经常使用的是CursorLoader,但是你也可以实现自己的子类。当loaders处于活动状态时,它应该监控其数据的来源,当内容改变时候显示新的结果。
AsyncTaskLoader
抽象的loader提供一个AsyncTask来处理工作。
CursorLoader
AsyncTaskLoader的子类,查询ContentResolver返回一个游标。这个类实现了Loader协议,对于游标查询在一个标准 的方式,建立在AsyncTaskLoader基础上,来执行游标查询在后台线程中,以至于不会中断应用程序的UI。从ContentProvider中 实现异步数据加载,而不是通过fragment或者Activity API来执行的管理查询,是最好的方式。
- 在应用中使用Loader
- 启动一个Loader
LoaderManager通过Activity或者Fragment来管理一个或者多个Loader实例。在一个Activity或者Fragment中仅仅只有一个LoaderManager。
你通常的可以通过Activity的onCreate()方法来初始化一个Loader,或者通过Fragment的onActivityCreated()方法。你可以按照下面的做:
//获得一个LoaderManager
LoaderManager manager = getLoaderManager();
//初始化Loader对象。
Loader loader = manager.initLoader(id, args, callback);
上面三个参数:
1、 一个唯一的Id标识,用于标示这个Loader
2、 构造函数的可选参数,可以为空
3、 LoaderManager.LoaderCallbacks的实现,LoaderManager调用来报告
Loader事件。
initLoader()调用,确保Loader被初始化,以及存在。它可能有两种结果:
1、 如果通过Id标识的Loader已经存在,上次被创建的Loader将会被重用。
2、 如果不存在的, 由ID标识的Loader,initLoader()方法触发 LoaderManager.LoaderCallbacks的onCreateLoader()方法 。这是你实现的代码来实例化并返回一个新的Loader。
- 使用LoaderManager进行回调
LoaderManager.LoaderCallbacks是一个回调接口,可以让客户端和LoaderManager交互。
回调接口共有三个回调方法:
public Loader< List<String>> onCreateLoader(int id, Bundle args) {
}
当您尝试访问一个loader(例如,通过loader中的initLoader()方法 ),它会检查是否存在指定的ID的loader。如果不存在,它会回调LoaderManager.LoaderCallbacks的onCreateLoader()方法,然后返回一个新的Loader
public void onLoadFinished(Loader<List<String>> loader, List<String> data) {}
这个方法是在前面已创建的加载器已经完成其加载过程后被调用.这个方法保证会在应用到加载器上的数据被释放之前被调用.在此方法中,你必须删除所有对旧数据的使用(因为它将很快会被删除),但是不要自己去释放它们,因为它们的加载器会做这些事情.
加载器一旦了解到应用不再使用数据时,将马上释放这些数据.例如,如果数据是一个从CursorLoader来的游标,你不应调用游标的close().如果游标被放置在一个CursorAdapter中,你应使用swapCursor()方法,以使旧的游标不被关闭(然后Loader会自动关闭旧的游标)
public void onLoaderReset(Loader<List<String>> loader) {
}
当一个已创建的加载器被重置从而使其数据无效时,此方法被调用.此回调使你能发现什么时候数据将被釋放于是你可以釋放对它的引用.
- Loader子类之---CursorLoader
CursorLoader是AsyncTaskLoader的子类。
使用方式基本同AsyncTaskLoader。
但是注意:
- 在创建CursorAdapter的时候,指明注册一个内容观测者。可以在Cursor的内容发送变化的时候,实现自动更新。
adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2,
null, new String[] {ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER },
new int[] { android.R.id.text1 ,android.R.id.text2},CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
- 当数据加载完毕的时候,在onLoadFinished()中来adapter.swapCursor(data);
- 当以前的Cursor不用的时候,不要手动关闭Cursor,可以在onLoaderReset()中 调用adapter.swapCursor(null);来废弃以前的Cursor。
//提示:联系人的Uri
Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
String DISPLAY_NAME =ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME;
String NUMBER = ContactsContract.CommonDataKinds.Phone.NUMBER
练习:结合使用searchview和listview,用cursorloader实现搜索联系人的功能。
提示:
重新加载数据:LoaderManager.restartLoader(int id, Bundle args, LoaderCallbacks<Cursor> callback)
筛选条件参数:"display_name like ?", new String[]{“%”+key+"%"},
注意:要想在用cursorLoader加载自定义的contenProvider的数据并实时更新数据内容的话,在自定义ContentProvider的query方法返回cursor之前的最后都需要有一句话:
cursor.setNotificationUri(getContext().getContentResolver(),uri);
这个方法用于给cursor注册一个内容观察者,当ContentProvider中的数据发生变化的时候调用getContext().getContentResolver().notifyChange(uri,null)来发出数据变化的消息,cursor的内容观察者收到消息后会回调第三方应用程序中的内容观察者的onChange方法。
- Loader子类之---AsyncTaskLoader
1、Activity(或者Fragment)要实现LoaderManager.LoaderCallbacks接口。至于继承于Activity还是FragmentActivity要看是否需要支持3.0以下版本。如果需要兼容则继承于FragmentActivity。
2、创建LoaderManager对象:通过getLoaderManager()或getSupportLoaderManager()方法来实现。如果是继承于FragmentActivity类,则使用getSupportLoaderManager()方法来创建LoaderManger对象,否则使用前者创建即可;
3、初始化Loader对象:调用initLoader()方法来初始化;
4、自定义Loader要继承于AsyncTaskLoader;
必须要有构造方法;
必须重写onStartLoading()、loadInBackground() 、deliverResult()。而且要在onStartLoading中必须调用forceLoad()才能依次调用下一个即将执行的方法。
在loadInBackground()方法中执行耗时操作;
在deliverResult()方法中执行跟适配器交换数据的操作。