Android Loader異步裝載

1、Loader簡介:
(一)、Loader的概念:

        裝載器從android3.0開始引進。它使得在activity或fragment中異步加載數據變得簡單。android

        當成批顯示數據的時候,爲了使用戶體驗更好,須要進行異步裝載。也就是說,讓未顯示數據的ListView等UI組件或控件先顯示,避免出現白屏的尷尬現象,同時在後臺下載數據,等下載完成後再更新ListView組件。這樣儘管用戶不會馬上看到數據,可是也不至於網絡速度緩慢或服務器響應不及時而形成假死現象。數據庫

 

裝載器具備以下特性:服務器

 

  • 它們對每一個Activity和Fragment都有效;網絡

  • 他們提供了異步加載數據的能力;app

  • 它擁有一個數據改變通知機制,當數據源作出改變時會及時通知。 也就是能夠監聽數據源,一旦數據源發生變化,Loader會感知這些變化;異步

  • 當Cursor 發生變化時,會自動加載數據,所以並不須要再從新進行數據查詢。ide

    android設計Loader的初衷是想讓你們像CursorLoader的作法同樣,經過loader去維護數據,每次啓動loader時先檢查有沒有舊的數據並把舊的數據先deliver給用戶,而後再考慮要不要從新加載新的數據。佈局

(二)、裝載器API概述:

        在使用裝載器時,會涉及不少類和接口們,在下表中對它們總結一下:this

Class/Interface 說明
LoaderManager

一個抽像類,關聯到一個Activity或Fragment,管理一個或多個裝載器的實例。這幫助一個應用管理那些與Activity或Fragment的生命週期相關的長時間運行的的操做。最多見的方式是與一個CursorLoader一塊兒使用,然而應用是能夠隨便寫它們本身的裝載器以加載其它類型的數據。
spa

每一個activity或fragment只有一個LoaderManager。可是一個LoaderManager能夠擁有多個裝載器。

LoaderManager.LoaderCallbacks 一個用於客戶端與LoaderManager交互的回調接口。例如,你使用回調方法onCreateLoader()來建立一個新的裝載器。
Loader(裝載器) 一個執行異步數據加載的抽象類。它是加載器的基類。你可使用典型的CursorLoader,可是你也能夠實現你本身的子類。一旦裝載器被激活,它們將監視它們的數據源而且在數據改變時發送新的結果
AsyncTaskLoader 提供一個AsyncTask來執行異步加載工做的抽象類。
CursorLoader AsyncTaskLoader的子類,它查詢ContentResolver而後返回一個Cursor。這個類爲查詢cursor以標準的方式實現了裝載器的協議,它的遊標查詢是經過AsyncTaskLoader在後臺線程中執行,從而不會阻塞界面。使用這個裝載器是從一個ContentProvider異步加載數據的最好方式。相比之下,經過fragment或activity的API來執行一個被管理的查詢就不行了。

二AsyncTaskLoader示例:

 (一)、AsyncTaskLoader 實現數據加載的步驟:

一、窗體Activity要實現LoaderManager.LoaderCallbacks<Cursor>接口。至於繼承於Activity仍是FragmentActivity要看是否須要支持3.0如下的版本。若是須要兼容則繼承與FragmentActivity。

2.建立LoaderManager對象,經過getLoaderManager()或getSupportLoaderManager()方法實現。若是是繼承FragmentActivity,則使用getSupportLoaderManager()方法建立,不然使用前者便可。

三、初始化LoaderManager對象,調用initLoader()方法來初始化;

  •     initLoader()方法有如下參數:
  1. 一個惟一ID來標識裝載器
  2. 可選的參數,用於裝載器初始化
  3. 一個LoaderManager.LoaderCallbacks的實現。被LoaderManager調用以報告裝載器的事件。通常窗體都實現了這個接口,因此傳的是它本身:this;
  •     initLoader()保證一個裝載器被初始化並激活.它具備兩種可能的結果:
  1. 若是Id所指的裝載器已經存在,那麼這個裝載器將被重用
  2. 若是裝載器不存在,initLoader()就出發LoaderManager.LoaderCallbacks中的毀掉方法onCreateLoader()。這是實例化並返回一個新的Loader的地方

四、操做ListView空間對象:先findViewByID(),而後setAdapter();

 【備註】此時必須使用SimpleCursorAdapter適配器,而構建適配器的時候,第三個參數Cursor設置爲null,最後一個參數:flags必須是:CursAdapter.FLAG_REGISTER_CONTENT_OBSERVER。

五、自定義Loader,做爲onCreateLoader()的返回值 

  •   自定義Loader要繼承於AsyncTaskLoader<Cursor>;
  • 必須有構造方法
  • 必須重寫onStartLoading()、loadInBackground()、deliverResult()。並且要在onStartLoading中調用forceLoad()才能依次調用下一個即將執行的方法
  1. 在loadInBackground()方法中執行數據庫查詢,返回Cursor;
  2. 在deliverResult()方法中執行跟適配器交換數據的操做。adapter.swapCursor(data)。
SimpleCursorAdapter構造方法的參數講解。
方法原型:new SimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to , int flags) ;
 
參數:
1)、Context context, 這個與 SimpleListItemFactory 相關的 ListView 所處運行上下文(context)。也就是這個 ListView 所在的 Activity。
2)、int layout, 顯示 list item 的 佈局文件。這個 layout 文件中至少要包含在 "to" 參數中命名的 views。
3)、Cursor c, 數據庫的光標( Cursor )。若是 cursor 無效,則該參數能夠爲 null
4)、String[] from, 指定 column 中的哪些列的數據將綁定(顯示)到 UI 中。若是 cursor 無效, 則該參數可爲 null。
5)、int[] to, 指定用於顯示 "from" 參數指定的數據列表的 views。 這些 views 必須都是 TextViews。 "from" 參數的前 N 個值(valus)和 "to" 參數的前 N 個 views 是一一對應的關係。若是 cursor 無效,則該參數可爲 null。
6)、flags,用於定義適配器行爲的標誌位
  •  Flags used to determine the behavior of the adapter; may be any combination of FLAG_AUTO_REQUERY andFLAG_REGISTER_CONTENT_OBSERVER。
  •  FLAG_AUTO_REQUERY(常量值:1 )從 API11 開始已經廢棄。由於他會在應用程序的 UI 線程中執行遊標查詢操做, 致使響應緩慢甚至應用程序無響應(ANR)的錯誤。做爲替代方案,請使用 LoaderManager 和 AsyncTaskLoaderCursorLoader。
  • 若是設置FLAG_REGISTER_CONTENT_OBSERVER(常量值:2),適配器會在Cursor上註冊一個內容觀測器,當通知到達時會調用 onContentChanged() 方法。

 

(二)、LoaderManager.LoaderCallbacks主要回調方法:

 

一、onCreateLoader() :初始化並返回一個新的Loader;

 

當你試圖去操做一個裝載器時(好比,經過initLoader()),會檢查是否指定ID的裝載器已經存在.若是它不存在,將會觸發LoaderManager.LoaderCallbacks 的方法onCreateLoader();

 

 

 

二、onLoadFinished():當一個裝載器完成了它的裝載過程後被調用;

 

這個方法是在前面已建立的裝載器已經完成其加載過程後被調用.這個方法保證會在應用到裝載器上的數據被釋放以前被調用;

 

 

 

三、onLoaderReset() :當一個裝載器被重置而其數據無效時被調用。

 

        所謂Loader的重置,就是指Loader對象還保留,只是清除Loader中的數據,因此onLoaderReset()方法至關於Loader的銷燬方法。所以在onLoaderReset()方法中會找到即將釋放的數據的引用,並移除這些引用。移除引用後,GC才能夠清除這些數據。

 

當一個已建立的裝載器被重置從而使其數據無效時,此方法被調用.此回調使你能發現何時數據將被釋放。你能夠釋放對它的引用。

(四)、AsyncTaskLoader中各個方法的執行順序:

04-01 04:00:25.477: MainActivity: ==onCreate
04-01 04:00:25.701: LoaderCallbacks: ==onCreateLoader
04-01 04:00:25.705: AsyncTaskLoader: ==onStartLoading
04-01 04:00:25.709: AsyncTaskLoader: ==loadInBackground
04-01 04:00:25.721: AsyncTaskLoader: ==deliverResult
04-01 04:00:25.721: LoaderCallbacks: ==onLoadFinished
04-01 04:00:25.749: MainActivity: ==onStart
04-01 04:00:25.749: MainActivity: ==onResume
04-01 04:00:25.973: MainActivity: ==onCreateOptionsMenu

(五)、當另外一個app修改了同一個數據源(如:共同使用的SDCard上的數據庫)後AsyncTaskLoader中各個方法的執行順序:

04-01 04:01:06.693: MainActivity: ==onPause
04-01 04:01:08.413: MainActivity: ==onStop
04-01 04:01:15.721: AsyncTaskLoader: ==onStartLoading
04-01 04:01:15.721: AsyncTaskLoader: ==loadInBackground
04-01 04:01:15.721: AsyncTaskLoader: ==deliverResult
04-01 04:01:15.721: LoaderCallbacks: ==onLoadFinished
04-01 04:01:15.757: MainActivity: ==onStart
04-01 04:01:15.757: MainActivity: ==onResume

(三)、示例代碼:

publicclass MainActivity extends FragmentActivity implements LoaderManager.LoaderCallbacks<Cursor> {

private ListView listView_main;

private LoaderManager manager;

privatestatic SimpleCursorAdapter adapter;




@Override

protectedvoid onCreate(Bundle arg0) {

super.onCreate(arg0);

setContentView(R.layout.activity_main);

listView_main = (ListView) findViewById(R.id.listView_main);




manager = getSupportLoaderManager();

manager.initLoader(0, null, this);




adapter = new SimpleCursorAdapter(this, R.layout.item_listview_main,

null, new String[] { "_id", "title" }, newint[] {

R.id.text_item_title, R.id.text_item_content }, 2);

listView_main.setAdapter(adapter);
}




@Override

public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {

Log.i("Activity", "===onCreateLoader");

returnnew MyLoader(this);

}




@Override

publicvoid onLoadFinished(Loader<Cursor> arg0, Cursor arg1) {

Log.i("Activity", "===onLoaderFinished");

adapter.swapCursor(arg1);

}




@Override

publicvoid onLoaderReset(Loader<Cursor> arg0) {

Log.i("Activity", "===onLoaderReset");

}




staticclass MyLoader extends AsyncTaskLoader<Cursor> {

private Context context;




public MyLoader(Context context) {

super(context);

this.context = context;

}




@Override

protectedvoid onStartLoading() {

super.onStartLoading();

Log.i("MyLoader", "===onStartLoading");



forceLoad();

}




@Override

public Cursor loadInBackground() {

Log.i("MyLoader", "===loadInBackground");

MySQLiteDatabaseHelper dbHelper = new MySQLiteDatabaseHelper();

Cursor cursor = dbHelper.selectCursor(

"select id as _id , title from android_info limit 0,20",

null);

deliverResult(cursor);

return cursor;

}




@Override

publicvoid deliverResult(Cursor data) {

Log.i("MyLoader", "===deliverResult");

super.deliverResult(data);

adapter.swapCursor(data);

}

}

}
相關文章
相關標籤/搜索