Loader 加載器

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包括進來,加載器使得在活動和碎片中更容易加載異步數據,它有這些特性:html

  • 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:在一個應用中使用加載器,可能有多個類和接口會被調用.它們總結於下表:android

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.下面部分將告訴你如何在應用中使用這些類和接口api

 

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應用中使用加載器,使用加載器的應用通常包括以下部分:app

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()這個方法帶有以下這些參數async

  • 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:該方法調用以確保一個加載器是被初始化和激活的,它有兩個可能的輸出結果:ide

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 callbackpost

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.ui

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.這是爲了對內容提供者進行查詢所須要的一套完整信息 Specifically, it needs:特別是,它須要"ContentProvider

  • 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.

相關文章
相關標籤/搜索