Loader 加载器

Introduced in Android 3.0, loaders make it easy to asynchronously load data in an activity or fragment. Loaders have these characteristics:在Android3.0包括进来,加载器使得在活动和碎片中更容易加载异步数据,它有这些特性:

  • They are available to every Activity and Fragment.可用于每个ActivityFragment
  • They provide asynchronous loading of data.它们提供了异步数据的装载
  • They monitor the source of their data and deliver new results when the content changes.它们监视数据的源,并当内容改变时传递新结果
  • They automatically reconnect to the last loader's cursor when being recreated after a configuration change. Thus, they don't need to re-query their data.在配置改变后,重新创建时,它们会自动重新联接最后的加载器指针,因此,它们不需要重新查询它们的数据

Loader API Summary加载器

There are multiple classes and interfaces that may be involved in using loaders in an application. They are summarized in this table:在一个应用中使用加载器,可能有多个类和接口会被调用.它们总结于下表:

Class/Interface Description
LoaderManager An abstract class associated with an Activity or Fragment for managing one or more Loader instances.一个关联到一个Activity活动和Fragment碎片的抽象类,用于管理一个或多个Loader加载器实例. This helps an application manage longer-running operations in conjunction with the Activity or Fragment lifecycle加载管理器结合Activity活动和Fragment碎片的生命周期,有助于应用管理长期运行的操作; the most common use of this is with a CursorLoader, however applications are free to write their own loaders for loading other types of data加载管理器最常用的是CursorLoader,然而应用可以自由的写它们自己的加载器,来加其他的数据类型.
There is only one LoaderManager per activity or fragment每个活动或者碎片只能有一个LoaderManager加载管理器. But a LoaderManager can have multiple loaders但一个LoaderManager加载管理器可以有多个加载器.
LoaderManager.LoaderCallbacks A callback interface for a client to interact with the LoaderManagerLoaderManager加载管理器交互的客户端回调接口. For example, you use the onCreateLoader() callback method to create a new loader例如,你用onCreateLoader()回调方法创建一个新的加载器.
Loader An abstract class that performs asynchronous loading of data一个异步数据加载器. This is the base class for a loader这是加载器的基类. You would typically use CursorLoader, but you can implement your own subclass一般你可能用CursorLoader,但你可以实现自己的子类. While loaders are active they should monitor the source of their data and deliver new results when the contents change当加载器被激活,它们应该监视它们的数据源,并当数据源改变时传递新的结果.
AsyncTaskLoader Abstract loader that provides an AsyncTask to do the work提供一个AsyncTask来处理工作的抽象加载器.
CursorLoader A subclass of AsyncTaskLoader that queries the ContentResolver and returns a Cursor.查询ContentResolver内容解释器并返回一个Cursor指针,AsyncTaskLoader类的子数 This class implements the Loader protocol in a standard way for querying cursors, building on AsyncTaskLoader to perform the cursor query on a background thread so that it does not block the application's UI.这个类实现了一个标准的方法来查询指针(指示器),构建于AsyncTaskLoader之上,在一个后台线执行指针查询,所以不会阻塞应用的UI .Using this loader is the best way to asynchronously load data from a ContentProvider, instead of performing a managed query through the fragment or activity's APIs.使用这个加载器异步加载来自内容提供者的数据是一个最好的方法,而不是通过碎片和活动的APIs,执行一个管理队列.

The classes and interfaces in the above table are the essential components you'll use to implement a loader in your application上表中的类和接口,是你在应用中实现一个加载器至关重要的组件. You won't need all of them for each loader you create, but you'll always need a reference to the LoaderManager in order to initialize a loader and an implementation of a Loader class such as CursorLoader. 你所创建的加载器,并不需要所有这些组件和接口,但是为了初始化一个加载器及实现一个像CursorLoader这样的Loader加载器的类,你总是需要一个LoaderManager加载管理器的一个引用。The following sections show you how to use these classes and interfaces in an application.下面部分将告诉你如何在应用中使用这些类和接口

 

Using Loaders in an Application在应用中使用加载器

This section describes how to use loaders in an Android application. An application that uses loaders typically includes the following:这部分描述如何在Android应用中使用加载器,使用加载器的应用一般包括如下部分:

Starting a Loader开始加载

The LoaderManager manages one or more Loader instances within an Activity or Fragment.在一个Activity活动或者Fragment碎片中,LoaderManager加载管理器管理一个或多个Loader加载器, There is only one LoaderManager per activity or fragment.每个活动或者碎片中只有一个LoaderManager加载管理器.

You typically initialize a Loader within the activity's onCreate() method, or within the fragment's onActivityCreated() method. You do this as follows:你一般会在活动的onCreate()方法中,或者在一个碎片的onActivityCreated()方法中,初始化一个Loader加载器.你会这样做:

// Prepare the loader.  Either re-connect with an existing one,
// or start a new one.
getLoaderManager
().initLoader(0,null,this);

The initLoader() method takes the following parameters:initLoader()这个方法带有如下这些参数

  • A unique ID that identifies the loader. In this example, the ID is 0.标识加载器的唯一ID,在这个例子中,该ID是0
  • Optional arguments to supply to the loader at construction (null in this example).给加载器在构造时使用的可选参数(在本例子中是空)
  • A LoaderManager.LoaderCallbacks implementation, which the LoaderManager calls to report loader events.一个用于LoaderManager加载管理器,调用来报告加载事件的LoaderManager.LoaderCallbacks实现 In this example, the local class implements the LoaderManager.LoaderCallbacks interface, so it passes a reference to itself, this.在本例中局部内实现了LoaderManager.LoaderCallbacks接口,所以它传递了它自己,this.

The initLoader() call ensures that a loader is initialized and active. It has two possible outcomes:该方法调用以确保一个加载器是被初始化和激活的,它有两个可能的输出结果:

In either case, the given LoaderManager.LoaderCallbacks implementation is associated with the loader, and will be called when the loader state changes无论那种情况,上面给定的LoaderManager.LoaderCallbacks实现,都与加载器相关联,并且当加载器的状态改变时将被调用. If at the point of this call the caller is in its started state, and the requested loader already exists and has generated its data, then the system calls onLoadFinished() immediately (during initLoader()), so you must be prepared for this to happen. See onLoadFinished for more discussion of this callback

Note that the initLoader() method returns the Loader that is created, but you don't need to capture a reference to it.注意initLoader()方法返回一个被创建的Loader加载器,但你不需要捕获该加载器的引用. The LoaderManager manages the life of the loader automatically.加载管理器LoaderManager自动管理加载器的生命. The LoaderManager starts and stops loading when necessary, and maintains the state of the loader and its associated content,当必要时,加载管理器启动或停止加载器,并维持加载器的状态及与它相关的内容. As this implies, you rarely interact with loaders directly (though for an example of using loader methods to fine-tune a loader's behavior, see the LoaderThrottle sample). 这意味着,你很少需要直接与加载器交互(但做为一个使用加载器的举例,微调了加载器的行为,请看 LoaderThrottle例子)You most commonly use the LoaderManager.LoaderCallbacks methods to intervene in the loading process when particular events occur当某特殊事件发生时,你经常需要用LoaderManager.LoaderCallbacks的方法来干涉加载过程. For more discussion of this topic, see Using the LoaderManager Callbacks.关于本主题的详细讨论,参考Using the LoaderManager Callbacks.

Restarting a Loader重启加载器

When you use initLoader(), as shown above, it uses an existing loader with the specified ID if there is one.如上所述,当你使用initLoader()时,如果有一个加载器,它将使用由ID指定的已存在的加载器.If there isn't, it creates one.如果没有的话,它将创建一个. But sometimes you want to discard your old data and start over.但有时候,你想扔掉旧的数据并重新开始

To discard your old data, you use restartLoader().要扔掉你的旧数据,你要用restartLoader()方法 For example, this implementation of SearchView.OnQueryTextListener restarts the loader when the user's query changes.比如这个例子,当用户查询改变时,SearchView.OnQueryTextListener的实现,重启了加载器. The loader needs to be restarted so that it can use the revised search filter to do a new query:这个加载器重新启动,为了能使用改进的搜索过滤器进行新的查询.

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

Using the LoaderManager Callbacks使用加载管理器回调

LoaderManager.LoaderCallbacks is a callback interface that lets a client interact with the LoaderManager.LoaderManager.LoaderCallbacks是一个回调接口,客户端可以通过它与加载管理器LoaderManager交互.

Loaders, in particular CursorLoader, are expected to retain their data after being stopped.加载器,特别是CursorLoader加载器,期望在被停止后,能驻留它们的数据 This allows applications to keep their data across the activity or fragment's onStop() and onStart() methods, so that when users return to an application, they don't have to wait for the data to reload.这使得应用,能保持它们的数据跨越活动或者碎片的onStop()onStart()方法,以便当用户返回某个应用时,它们不必等待重新加载它们的数据。 You use the LoaderManager.LoaderCallbacks methods when to know when to create a new loader, and to tell the application when it is time to stop using a loader's data.你使用LoaderManager.LoaderCallbacks方法,知道什么时创建一个新的加载器,并告诉加载器什么时候该停止使用加载器的数据.

LoaderManager.LoaderCallbacks includes these methods:它包括这些方法

  • onLoadFinished() — Called when a previously created loader has finished its load.当前一个创建的加载器已完成了它的加载时,调用
  • onLoaderReset() — Called when a previously created loader is being reset, thus making its data unavailable.当先前创建的加载器,正在复位时调用,并使它的数据不可用.

These methods are described in more detail in the following sections.下面将详细讨论这些方法.

onCreateLoader响应创建加载器

When you attempt to access a loader (for example, through initLoader()), it checks to see whether the loader specified by the ID exists.当你尝试访问加载器(比如,通过initLoader()),它会检查由ID标识的加载器是否存在。 If it doesn't, it triggers the LoaderManager.LoaderCallbacks method onCreateLoader().如果不存在,它将触发LoaderManager.LoaderCallbacks方法onCreateLoader(). This is where you create a new loader. Typically this will be a CursorLoader, but you can implement your own Loader subclass.你在这里创建新加载器,一般是CursorLoader加载器,但也可以实现自己的Loader子类.

In this example, the onCreateLoader() callback method creates a CursorLoader. 在这个例子中,onCreateLoader()回调方法创建一个CursorLoader.You must build the CursorLoader using its constructor method, which requires the complete set of information needed to perform a query to the ContentProvider.你必须用它的构造方法构造CursorLoader.这是为了对内容提供者ContentProvider进行查询所需要的一套完整信息 Specifically, it needs:特别是,它需要"

  • uri — The URI for the content to retrieve.提取内容的URI
  • projection — A list of which columns to return. Passing null will return all columns, which is inefficient.返回列表中的那一列,传递null,将返回所有列,这样的话没有效率.
  • selection — A filter declaring which rows to return, formatted as an SQL WHERE clause (excluding the WHERE itself). Passing null will return all rows for the given URI.返回那些行的过滤声明,格式化像SQL WHERE语句(包括WHERE自己),传递null将返给定URI的所有行.
  • selectionArgs — You may include ?s in the selection, which will be replaced by the values from selectionArgs, in the order that they appear in the selection. The values will be bound as Strings.你可能在selection中包括 ?s.它将被selectionArgs的值替代,它们将依次出现在selection中,这些值将邦定成字串(be bound as 应该是这意思吧)
  • sortOrder — How to order the rows, formatted as an SQL ORDER BY clause (excluding the ORDER BY itself). Passing null will use the default sort order, which may be unordered.怎样排序行,格式化成SQL ORDER BY(包括ORDER BY自己),传递null将使用默认顺序,这样的话可能是无序的.

For example:

 // If non-null, this is the current filter the user has provided.
String mCurFilter;
...
publicLoader<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.
   
Stringselect="(("+Contacts.DISPLAY_NAME +" NOTNULL) AND ("
           
+Contacts.HAS_PHONE_NUMBER +"=1) AND ("
           
+Contacts.DISPLAY_NAME +" != '' ))";
   
returnnewCursorLoader(getActivity(), baseUri,
            CONTACTS_SUMMARY_PROJECTION
,select,null,
           
Contacts.DISPLAY_NAME +" COLLATE LOCALIZED ASC");
}

onLoadFinished

This method is called when a previously created loader has finished its load. 当预先创建的加载器完成了它的加载时,调用本方法.This method is guaranteed to be called prior to the release of the last data that was supplied for this loader.这个方法保证会在,释放本加载器的最后的数据前会调用。 At this point you should remove all use of the old data (since it will be released soon), but should not do your own release of the data since its loader owns it and will take care of that.在你在这一点移除所有用过的旧数据(因为它即将释放),但你不应该释放加载器捅有的和将要关心的数据。

The loader will release the data once it knows the application is no longer using it.一旦知道应用将不再使用该数据,加载器将释放该数据 For example, if the data is a cursor from a CursorLoader, you should not call close() on it yourself. 比如,如果数据是一个CursorLoader的cursor,你不应自己对其调用close()方法.If the cursor is being placed in a CursorAdapter, you should use the swapCursor() method so that the old Cursor is not closed.如果cursor将被放到一个CursorAdapter中,你应使swapCursor()方法,以便旧的Cursor不被关闭. For example:

// This is the Adapter being used to display the list's data.这是一个用于显示列表的数据的适配器
SimpleCursorAdapter mAdapter;
...

publicvoid onLoadFinished(Loader<Cursor> loader,Cursor data){
   
// Swap the new cursor in.  (The framework will take care of closing the
   
// old cursor once we return.)把新的cursor交换进来,一旦我们返回,框架将负责关闭旧的cursor.
    mAdapter
.swapCursor(data);
}

onLoaderReset

This method is called when a previously created loader is being reset, thus making its data unavailable.当预选创建的加载器正在复位时,调用本方法,因此使得它的数据不可用. This callback lets you find out when the data is about to be released so you can remove your reference to it.  这个回调让你找出什么时候数据将被释放,以便你能移除对它的引用

This implementation calls swapCursor() with a value of null:这个实现调用一个带null值的swapCursor()方法.

// This is the Adapter being used to display the list's data.
SimpleCursorAdapter mAdapter;
...

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

Example举例

As an example, here is the full implementation of a Fragment that displays a ListView containing the results of a query against the contacts content provider.这是一个碎片的完全实现的例子,显示一个列表视图,该视图是对通信录内容提供者的查询结果, It uses a CursorLoader to manage the query on the provider.它用一个CursorLoader管理对内容提供者的查询.

For an application to access a user's contacts, as shown in this example, its manifest must include the permission READ_CONTACTS.这是一个展示了访问用户通信录的例子,它的manifest必须包括READ_CONTACTS权限.

publicstaticclassCursorLoaderListFragmentextendsListFragment
       
implementsOnQueryTextListener,LoaderManager.LoaderCallbacks<Cursor>{

   
// This is the Adapter being used to display the list's data.
   
SimpleCursorAdapter mAdapter;

   
// If non-null, this is the current filter the user has provided.
   
String mCurFilter;

   
@Overridepublicvoid onActivityCreated(Bundle savedInstanceState){
       
super.onActivityCreated(savedInstanceState);

       
// Give some text to display if there is no data.  In a real
       
// application this would come from a resource.
        setEmptyText
("No phone numbers");

       
// We have a menu item to show in action bar.
        setHasOptionsMenu
(true);

       
// Create an empty adapter we will use to display the loaded data.
        mAdapter
=newSimpleCursorAdapter(getActivity(),
                android
.R.layout.simple_list_item_2,null,
               
newString[]{Contacts.DISPLAY_NAME,Contacts.CONTACT_STATUS },
               
newint[]{ android.R.id.text1, android.R.id.text2 },0);
        setListAdapter
(mAdapter);

       
// Prepare the loader.  Either re-connect with an existing one,
       
// or start a new one.
        getLoaderManager
().initLoader(0,null,this);
   
}

   
@Overridepublicvoid onCreateOptionsMenu(Menu menu,MenuInflater inflater){
       
// Place an action bar item for searching.
       
MenuItem item = menu.add("Search");
        item
.setIcon(android.R.drawable.ic_menu_search);
        item
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
       
SearchView sv =newSearchView(getActivity());
        sv
.setOnQueryTextListener(this);
        item
.setActionView(sv);
   
}

   
publicboolean onQueryTextChange(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);
       
returntrue;
   
}

   
@Overridepublicboolean onQueryTextSubmit(String query){
       
// Don't care about this.
       
returntrue;
   
}

   
@Overridepublicvoid onListItemClick(ListView l,View v,int position,long id){
       
// Insert desired behavior here.
       
Log.i("FragmentComplexList","Item clicked: "+ id);
   
}

   
// These are the Contacts rows that we will retrieve.
   
staticfinalString[] CONTACTS_SUMMARY_PROJECTION =newString[]{
       
Contacts._ID,
       
Contacts.DISPLAY_NAME,
       
Contacts.CONTACT_STATUS,
       
Contacts.CONTACT_PRESENCE,
       
Contacts.PHOTO_ID,
       
Contacts.LOOKUP_KEY,
   
};
   
publicLoader<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.
       
Stringselect="(("+Contacts.DISPLAY_NAME +" NOTNULL) AND ("
               
+Contacts.HAS_PHONE_NUMBER +"=1) AND ("
               
+Contacts.DISPLAY_NAME +" != '' ))";
       
returnnewCursorLoader(getActivity(), baseUri,
                CONTACTS_SUMMARY_PROJECTION
,select,null,
               
Contacts.DISPLAY_NAME +" COLLATE LOCALIZED ASC");
   
}

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

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

More Examples更多例子

There are a few different samples in ApiDemos that illustrate how to use loaders:在ApiDemos 中有更多关于如何使用加载器的例子

  • FragmentListCursorLoader — A complete version of the snippet shown above.显示在上面片断代码的完全版本
  • LoaderThrottle — An example of how to use throttling to reduce the number of queries a content provider does then its data changes.一个展示了当数据改变时,怎样使用throttling减少对内容提供者的查询次数的例子

For information on downloading and installing the SDK samples, see Getting the Samples.关于下载和安装SDK例子,参考 Getting the Samples.


 


 


 


 

你可能感兴趣的:(loader)