Loader在android3.0以后出現(xiàn),它可以使Activity和Fragment異步加載數(shù)據(jù)變得簡單
當(dāng)成批顯示數(shù)據(jù)時,為了使用戶的體驗更好,需要進行異步裝載,也就是說,讓未顯示數(shù)據(jù)的ListView等UI組件或控件先顯示,避免出現(xiàn)白屏的尷尬現(xiàn)象,同時在后臺下載數(shù)據(jù),等下載完成后再更新ListView組件。這樣盡管用戶不會立刻看到數(shù)據(jù),但是也不至于網(wǎng)絡(luò)速度緩慢或服務(wù)器響應(yīng)不及時而造成假死現(xiàn)象。
Loader的特性:
- 它對每個Activity和Fragment都有效
- 它提供了異步加載數(shù)據(jù)的能力
- 它擁有一個數(shù)據(jù)改變通知機制,當(dāng)數(shù)據(jù)源做出改變時會及時通知。也就是可以監(jiān)聽數(shù)據(jù)源,一旦數(shù)據(jù)源發(fā)生變化,Loader會感知這些變化
- 當(dāng)Cursor發(fā)生變化時,會自動加載數(shù)據(jù),因此不需要再重新進行數(shù)據(jù)查詢
API概述
- LoaderManager
一個抽像類,關(guān)聯(lián)到一個Activity或Fragment,管理一個或多個裝載器的實例。這幫助一個應(yīng)用管理那些與Activity或Fragment的生命周期相關(guān)的長時間運行的的操作。最常見的方式是與一個CursorLoader一起使用,然而應(yīng)用是可以隨便寫它們自己的裝載器以加載其它類型的數(shù)據(jù)。
每個activity或fragment只有一個LoaderManager。但是一個LoaderManager可以擁有多個裝載器。 - LoaderManager.LoaderCallbacks
一個用于客戶端與LoaderManager交互的回調(diào)接口。例如,你使用回調(diào)方法onCreateLoader()來創(chuàng)建一個新的裝載器。 - Loader(裝載器)
一個執(zhí)行異步數(shù)據(jù)加載的抽象類。它是加載器的基類。你可以使用典型的CursorLoader,但是你也可以實現(xiàn)你自己的子類。一旦裝載器被激活,它們將監(jiān)視它們的數(shù)據(jù)源并且在數(shù)據(jù)改變時發(fā)送新的結(jié)果。 - AsyncTaskLoader
提供一個AsyncTask來執(zhí)行異步加載工作的抽象類。 - CursorLoader
AsyncTaskLoader的子類,它查詢ContentResolver然后返回一個Cursor。這個類為查詢cursor以標(biāo)準(zhǔn)的方式實現(xiàn)了裝載器的協(xié)議,它的游標(biāo)查詢是通過AsyncTaskLoader在后臺線程中執(zhí)行,從而不會阻塞界面。使用這個裝載器是從一個ContentProvider異步加載數(shù)據(jù)的最好方式。相比之下,通過fragment或activity的API來執(zhí)行一個被管理的查詢就不行
使用Loader的步驟
- 在Activity或者Fragment中,實現(xiàn)LoaderCallBack<Cursor>接口,并且聲明加載數(shù)據(jù)結(jié)果的返回類型,重寫父類的三個方法
Loader<Cursor> onCreateLoader(int id, Bundle args) //創(chuàng)建新的Loader,加載新的數(shù)據(jù)
void onLoadFinished(Loader<Cursor> loader, Cursor data) //加載數(shù)據(jù)完成后執(zhí)行
void onLoaderReset(Loader<Cursor> loader) //在Loader加載數(shù)據(jù)之前,重置之前的數(shù)據(jù) - 在Activity或者Fragment的初始化階段的生命周期方法中 初始化啟動Loader
/**
* id Loader的編號
* args Loader加載數(shù)據(jù)的條件
* callback Loader接口回調(diào)的方法
*/
getLoaderManager().initLoader(id, args, callback); - 在LoaderCallBacks的創(chuàng)建新的Loader的方法中(onCreateLoader) 實例化CursorLoader對象
CursorLoader loader = new CursorLoader(context, uri, projection, selection, selectionArgs, sortOrder)
//CursorLoader 內(nèi)部使用了CotentResolver 加載ContentProvider暴露出來的數(shù)據(jù),通過URI內(nèi)置CotentObserver,監(jiān)聽數(shù)據(jù)源的變化 - 在LoaderCallBacks的加載數(shù)據(jù)完成的方法中(onLoadefinished) 將加載完成的數(shù)據(jù)顯示在ListView中
adapter.changeCursor(arg1); - 在LoaderCallBacks的重置方法中(onLoaderReset), 清除之前的舊數(shù)據(jù)
adapter.changeCursor(null);
自定義Loader
- 定義一個類, 繼承AsyncTaskLoader<D> ,聲明返回結(jié)果的類型
- 重寫方法 onStartLoading() , 執(zhí)行方法: forceLoader()強制執(zhí)行后臺的方法, 加載數(shù)據(jù)
- 重寫父類的方法 loadInBackground() , 在此方法中執(zhí)行獲取數(shù)據(jù)的操作, 并將結(jié)果返回
- 構(gòu)造方法
實例(自定義Loader加載短信內(nèi)容)
-
MainActivity.java
public class MainActivity extends Activity implements LoaderCallbacks<Cursor> {
private ListView lv;
private SearchView sv;
private SimpleCursorAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);lv = (ListView) findViewById(R.id.lv); sv = (SearchView) findViewById(R.id.sv); adapter = new SimpleCursorAdapter(this, R.layout.item_lv, null, new String[]{"address","body"}, new int[]{R.id.address,R.id.body}, SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER); lv.setAdapter(adapter); getLoaderManager().initLoader(1, null, this); sv.setOnQueryTextListener(new OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { // TODO Auto-generated method stub return false; } @Override public boolean onQueryTextChange(String newText) { // TODO Auto-generated method stub Bundle bundle = new Bundle(); bundle.putString("key", newText); getLoaderManager().restartLoader(1, bundle, MainActivity.this); return false; } }); } @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { // TODO Auto-generated method stub MyLoader loader = new MyLoader(this,args); return loader; } @Override public void onLoadFinished(Loader<Cursor> arg0, Cursor arg1) { // TODO Auto-generated method stub adapter.changeCursor(arg1); } @Override public void onLoaderReset(Loader<Cursor> arg0) { // TODO Auto-generated method stub adapter.changeCursor(null); } } -
MyLoader
public class MyLoader extends AsyncTaskLoader<Cursor> {private Bundle bundle; private Uri uri = Uri.parse("content://sms"); private String []colums = {"_id","address","body"}; public MyLoader(Context context,Bundle bundle) { super(context); // TODO Auto-generated constructor stub this.bundle = bundle; } @Override protected void onStartLoading() { // TODO Auto-generated method stub super.onStartLoading(); forceLoad(); } @Override public Cursor loadInBackground() { // TODO Auto-generated method stub String selection = null; String[] selectionArgs = null; if (bundle!=null) { selection = "body like ? "; selectionArgs = new String[]{"%"+bundle.getString("key")+"%"}; } Cursor cursor = getContext().getContentResolver().query(uri, colums, selection, selectionArgs, null); return cursor; } }