Android Loader 官方教程翻譯

Loadershtml

目錄android

1.     Loader API 簡介api

2.     在應用中使用Loaderapp

1.     啓動一個Loader異步

2.     重啓一個Loaderasync

3.     使用Loader管理器LoaderManager 的回調方法ide

3.     實例ui

1.     更多實例this

主類spa

1.     LoaderManager

2.     Loader

相關

1.     LoaderCursor

2.     LoaderThrottle

 


 

Loader是在Android 3.0引入的一個API,使用LoaderActivityFragment中異步加載數據會變得更加容易。Loaders具備下面這些特徵:

·         在每一個Activity  Fragment中都有效

·         提供異步加載數據

·         可監控數據源並在內容改變時傳遞新的結果

·         當配置更改,Loader被重寫建立時,會自動從新鏈接到最近的遊標處。所以,不須要從新發起數據請求。

Loader API 簡介

有多個類和接口可能會在應用中使用到Loader。這些類或接口以下:

Class/Interface

描述

LoaderManager

被關聯到一個Activity或者Fragment的抽象類,用於管理一個或多個Loader接口。幫助應用程序管理在Activity或者Fragment中耗時長的操做;最多見的是結合 CursorLoader 一塊兒使用。在應用程序中能夠自由地編寫本身的Loader加載其餘類型的數據。

    每個Activity或Fragment只有一個LoaderManager,可是一個LoaderManage能夠有多個Loader。

LoaderManager.LoaderCallbacks

    客戶端與LoaderManager交互的回調接口。例如,你可使用onCreateLoader() 回調方法建立一個新的Loader。

Loader

執行異步加載數據的抽象類。這是一個具體loader的基類。你可使用具備表明性的CursorLoader,但你也能夠實現你本身的子類。當Loader被激活,他們就會監測數據源而且當內容改變的時候返回新的結果。

AsyncTaskLoader

一個抽象loader。提供了一個AsyncTask 完成須要的操做。

CursorLoader

A subclass of AsyncTaskLoader that queries the ContentResolver and returns a Cursor. 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.   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.

 AsyncTaskLoader 的一個子類,用於獲取ContentResolver 和返回一個 Cursor.這個類使用標準的方式實現了Loader,用於獲取遊標。繼承AsyncTaskLoader 使其能在後臺線程中執行獲取遊標的操做,不至於堵塞UI線程。從ContentProvider中異步加載數據的最佳方式就是使用這個類。

  

上面表格中列舉的類和接口都是在應用程序中實現加載器loader的重要組成部分。建立每個Loader的時候並非都須要使用到這些類和接口,可是你總會須要一份LoaderManager 的參考,用於初始化一個loader和實現一個Loader,例如  CursorLoader. 下面的章節將會告訴你怎麼在你的應用程序中使用這些類和接口。

在應用中使用加載器Loader

    這個章節介紹了怎麼在一個Android應用中使用加載器Loader。使用加載器通常須要如下內容:

·         一個Activity  Fragment.

·         LoaderManager的一個實例。

·         一個 CursorLoader 用於從 ContentProvider加載數據。或者你能夠實現Loader 或者 AsyncTaskLoader 的子類,用於從其餘數據源加載數據。

·          LoaderManager.LoaderCallbacks. 的一個實現。這是建立新的loaders和引用已經存在的loaders的地方。

·         一種展現數據的方式,如SimpleCursorAdapter.

·         一個數據源,如,當使用 CursorLoader.的時候,使用ContentProvider

開啓一個 Loader

LoaderManagerActivity或者Fragment中管理一個或多個Loader實例。一個ActivityFragment只有一個LoaderManager。一般須要在ActivityonCreate()方法或者FragmentonActivityCreated()方法中初始化一個Loader。示例以下:

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

initLoader() 的參數解析:

·         Loader的惟一ID.在這個例子中,ID0

·         構建loader時的可選參數。 (null in this example).

·         一個LoaderManager.LoaderCallbacks 的實現LoaderManager 調用這個實現來響應Loader的事件. 在這個例子中,當前的類實現了 LoaderManager.LoaderCallbacks 接口,因此傳遞了一個引用給本身。

.

調用 initLoader() 一個Loader被初始化並激活。存在兩種可能的結果:

·         If the loader specified by the ID already exists, the last created loader is reused.若是指定的ID已經存在,那麼最近建立的loader就被複用。

·         若是指定的ID不存在,initLoader() 觸發LoaderManager.LoaderCallbacks方法  onCreateLoader().在這個方法裏實例化並返回一個新的loader。更多的討論,在章節 onCreateLoader

 

在這兩種狀況下,LoaderManager.LoaderCallbacks 的實現是跟loader相關聯的,當Loader的狀態改變時,這些回調方法將會被調用。當調用者在開啓狀態,且須要的Loader已經存在並已經得到數據,那麼系統將會當即調用回調方法onLoadFinished() ,更多關於該回調方法的討論,可查看onLoadFinished 部分。

須要注意的是,initLoader()方法建立並返回一個Loader,當你不須要去捕獲它的引用。LoaderManager 會自動管理這個loade的生命週期。當須要的時候,LoaderManager會開啓或中止加載數據,並維護loader的狀態和關聯的內容。這意味着,你不多會直接手動操做loader(這裏有一個微調loader行爲的例子,查看 LoaderThrottle 示例)。最常用 LoaderManager.LoaderCallbacks回調方法來干預加載過程當中發生的特定事件。更多關於該主題的討論,請查看Using the LoaderManager Callbacks

 

重啓一個Loader

當你像上面提到的那樣使用initLoader(),當參數中的ID已經存在,使用的是已經存在的loader,若是ID不存在,將會建立一個新的loader。但有時候,你再也不須要原來的數據並從新開始。

丟棄舊的數據,使用restartLoader()。以下面的例子,當查詢改變的時候,在SearchView.OnQueryTextListener 的實現中重啓loader。該Loader將須要從新啓動,以便它可使用修訂後的搜索過濾器作一個新的查詢。

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 交互的回調接口。

不少加載器,特別是CursorLoader,但願中止的時候可以保留它們數據。這個容許應用程序的ActivityFragment的狀態在onStop()  onStart() 之間變化時保留數據。所以,當用戶回到應用程序的時候,不須要等待數據加載。當你知道何時建立loader,而且知道何時中止使用loader的數據時,使用LoaderManager.LoaderCallbacks 回調方法。

LoaderManager.LoaderCallbacks 包括如下的回調方法:

·         onCreateLoader() — 從給定的ID中實例化並返回一個新的Loader.

·         onLoadFinished() — 當以前建立的loader完成數據加載後調用。

·         onLoaderReset() — Called when a previously created loader is being reset, thus making its data unavailable.當以前建立的loader被重置的時候調用,原來的數據會丟棄。

下面將對這些方法進行詳細的介紹。

onCreateLoader

When you attempt to access a loader (for example, through initLoader()), it checks to see whether the loader specified by the ID exists. If it doesn't, it triggers the LoaderManager.LoaderCallbacks method onCreateLoader(). This is where you create a new loader. Typically this will be a CursorLoader, but you can implement your ownLoader subclass.

當你企圖去訪問一個loader的時候(好比,經過initLoader(),它會先判斷給定IDloader是否存在,若是不存在,將會觸發該方法建立一個新的Loader。這一般是一個CursorLoader,可是你也能夠實現本身的Loader子類。

In this example, the onCreateLoader() callback method creates a CursorLoader. You must build theCursorLoader using its constructor method, which requires the complete set of information needed to perform a query to the ContentProvider. Specifically, it needs:

·         uri — The URI for the content to retrieve.

·         projection — A list of which columns to return. Passing null will return all columns, which is inefficient.

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

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

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

For example:

 // 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

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.

當加載器再也不使用數據的時候,它將會本身釋放這些數據。例如,若是數據來自CursorLoader,你不該該本身調用close() 若是cursor被設置在一個CursorAdapter裏,你應該使用 swapCursor() 方法,確保原來的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

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:

// This is the Adapter being used to display the list's data.
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);
}

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.

For an application to access a user's contacts, as shown in this example, its manifest must include the permission READ_CONTACTS.

public static class CursorLoaderListFragment extends ListFragment
       
implements OnQueryTextListener, 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;

   
@Override public void 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
= 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);

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

   
@Override public void 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 = new SearchView(getActivity());
        sv
.setOnQueryTextListener(this);
        item
.setActionView(sv);
   
}

   
public boolean 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);
       
return true;
   
}

   
@Override public boolean onQueryTextSubmit(String query) {
       
// Don't care about this.
       
return true;
   
}

   
@Override public void 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.
   
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) {
       
// 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");
   
}

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

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

More Examples

There are a few different samples in ApiDemos that illustrate how to use loaders:

&middot;         LoaderCursor — A complete version of the snippet shown above.

&middot;         LoaderThrottle — An example of how to use throttling to reduce the number of queries a content provider does when its data changes.

For information on downloading and installing the SDK samples, see Getting the Samples.

相關文章
相關標籤/搜索