Loader使得在Activity或者Fragment中更加容易地异步加载数据。Loader有以下三个特性:
1、他们可以在任意一个Acticvity或者Fragment中使用;
2、他们提供异步数据的加载;
3、当内容改变时,他们控制他们的数据源传输新的结果给Activity或者Fragment
4、当配置改变的时候他们被重新创建的时候,他们自动重新连接到上一次loader的指针所在的地方,因此不需要重新查询出数据。
那么我们如何在我们的Activity或者Fragment中使用Loader类呢?
一个应用程序用到loader基本需要包含以下几步:
1、一个Activity或者Fragmnet;
2、一个LoaderManager实例;
3、一个CurLoader实例用来加载ContentProvider返回的数据。或者,你也可以实现自己的Loader或者AsyncTaskLoader的子类用来加载其他资源的数据;
4、实现LoaderManager.LoaderCallbacks。在这个方法中实例化load或者管理已经存在的loader;
5、一种展示loader的数据的方式,例如SimpleCursorAdapter
.
6、一个数据源,例如当我们使用CurLoader的时候用Content Provider。
如何开启一个Loader呢?
LoaderManager在一个Activity或者Fragment中可以管理一个或者多个Loader,但是每一个Fragment或者Activity仅仅有一个LoaderManager。我们一般在Activity的onCreate方法中或者onActivityCreated方法中实例化一个Loader对象。
// Prepare the loader. Either re-connect with an existing one, // or start a new one. getLoaderManager().initLoader(0, null, this);这个initLoader方法需要三个参数:
1、一个Loader实例独一无二的ID;
2、在这个构造方法中是一个可选参数,一般为null;
3、一个LoaderManager.LoaderCallbacks的实现类。LoaderManager调用这个实现类去记录loader事件。在上面这个例子中,这个类本身实现了LoaderManager.LoaderCallbacks方法,因此传递一个this引用它自身。
这个initLoader方法调用使得这个loader被初始化和激活,这个方法可以返回两个结果。
如果这个Loader指定一个已经存在的loader ID,那么最近一次实例化的loader被重新利用;
但是如果这个Loader指定一个不能存在的Loader ID,initLoader()方法触发LoaderManager.LoaderCallbacks接口的onCreatedLoader方法,在这个方法中你实例化并返回一个新的loader对象。
无论以上的两种情况的哪一个,这个LoaderManager.LoaderCallbacks方法实现类和loader相关,并且在这个loader的状态改变的时候这个实现类就会被调用。如果这个接口在调用的时候,这个调用者的状态是开启状态并且这个loader已经存在,数据已经生成,系统会立刻自动调用onLoadFinished方法,因此你必须为这个要发生的准备着。
注意:initLoader方法返回被创建成功的loader,但是你不需要占用它的一个引用,LoaderManager会自动管理loader的生命周期。LoaderManager会根据需要开启和关闭一个Loader,管理loader的状态和它相关的内容。在整个应用过程中你会很少和loaders进行交互。在特殊的事件发生的时候,最常用的是在LoaderManager.LoaderCallbacks方法中阻塞数据加载的进程。
重启一个Loader
当我们使用loader的时候正如上面展示的一样,它使用了一个已经存在的ID的loader。如果不存在,则就会创建一个新的。但是有的时候我们想要丢弃掉我们旧的数据并且重新开启一个loader。这个时候我们就需要用到restartLoader方法。
public boolean onQueryTextChanged(String newText) { // Called when the action bar search text has changed. Update // the search filter, and restart the loader to do a new query // with this filter. mCurFilter = !TextUtils.isEmpty(newText) ? newText : null; getLoaderManager().restartLoader(0, null, this); return true; }如何使用LoaderManager的Callbacks各种回调方法?
LoaderManager.LoaderCallbacks是让一个客户端与LoaderManager交互的回调接口。
Loader,比较特殊的例如,CursorLoader,可以在他们停止的时候也可以保持它的数据。这就允许应用程序在Activity或者Fragment的onStop和onStart方法之间保持他们数据,这就使得当用户在返回到应用程序时,不必重新加载数据。
LoaderManager.LoaderCallBacks包括这些方法。
onCreateLoader()——初始化并且返回一个被给与ID的新的Loader;
onLoadFinished()——当一个事先创建的Loader完成它的load的时候调用;
onLoadReset()——当一个事先创建的Loader被reset并且使得数据不可用的时候调用;
onCreateLoader方法:
当你试图访问一个Loader的时候,系统会自动检查被指定ID的loader是否存在,如果不存在系统会触发LoaderManager.LoaderCallbacks的onCreateLoader方法,在这里创建一个新的Loader实例。我们可以使用系统定义好的,例如CursorLoader,也可以实现我们自己的load子类。
// If non-null, this is the current filter the user has provided. String mCurFilter; ... public Loader<Cursor> onCreateLoader(int id, Bundle args) { // This is called when a new Loader needs to be created. This // sample only has one Loader, so we don't care about the ID. // First, pick the base URI to use depending on whether we are // currently filtering. Uri baseUri; if (mCurFilter != null) { baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode(mCurFilter)); } else { baseUri = Contacts.CONTENT_URI; } // Now create and return a CursorLoader that will take care of // creating a Cursor for the data being displayed. 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"); }
onLoadFinished方法:
当新创建的loader完成加载数据时调用这个方法。这个方法被优先调用确保这个loader最后一次的数据被释放掉。这个时候你需要移除这些旧数据(即使它将要很快被释放掉)。
一旦loader知道应用程序不再使用它,它将要释放掉所有的数据。例如,如果一个数据是一个CursorLoader的一个Cursor,你不应该手动调用close()方法。如果这个cursor被CursorAdapt所替代,你应该使用swapCursor方法避免这个old Cursor被关闭。
// This is the Adapter being used to display the list's data. 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方法
当一个之前创建的loader被重置的时候调用这个方法,这个方法使得要被重置的loader的数据不再可用,这个回调方法让你找出数据将要什么时候被释放掉,因此你能移除掉这个数据的引用。
SimpleCursorAdapter mAdapter; ... public void onLoaderReset(Loader<Cursor> loader) { // This is called when the last Cursor provided to onLoadFinished() // above is about to be closed. We need to make sure we are no // longer using it. mAdapter.swapCursor(null); }