Loader的概念:
裝載器從android3.0開始引進。它使得在activity或fragment中異步加載資料(資料庫的資料,包括本地資料庫,包括共享資料庫)變得簡單。
裝載器具有如下特性:
- 它們對每個Activity和Fragment都有效;
- 他們提供了異步加載資料的能力;
- 它擁有一個資料改變通知機制,當資料源做出改變時會及時通知。 也就是可以監聽資料源,一旦資料源發生變化,Loader會感覺這些變化;
- 當Cursor 發生變化時,會自動加載資料,是以并不需要再重新進行資料查詢。
- android設計Loader的初衷是想讓大家像CursorLoader的做法一樣,通過loader去維護資料,每次啟動loader時先檢查有沒有舊的資料并把舊的資料先deliver給使用者,然後再考慮要不要重新加載新的資料。
裝載器API概述:
Class/Interface | 說明 |
---|---|
LoaderManager | 一個抽象類,關聯到一個Activity或Fragment,管理一個或多個裝載器的執行個體。這幫助一個應用管理那些與Activity或Fragment的生命周期相關的長時間運作的的操作。最常見的方式是與一個CursorLoader一起使用,然而應用是可以随便寫它們自己的裝載器以加載其它類型的資料。 每個activity或fragment隻有一個LoaderManager。但是一個LoaderManager可以擁有多個裝載器。 |
LoaderManager.LoaderCallbacks | 一個用于用戶端與LoaderManager互動的回調接口。例如,你使用回調方法onCreateLoader()來建立一個新的裝載器。onCreate, onFinish,onRestart |
Loader(裝載器) | 一個執行異步資料加載的抽象類。它是裝載器的基類。你可以使用典型的CursorLoader,但是你也可以實作你自己的子類。一旦裝載器被激活,它們将監視它們的資料源并且在資料改變時發送新的結果。 |
AsyncTaskLoader | 提供一個AsyncTask來執行異步加載工作的抽象類。(可以處理任何的資料源,當然可以處理cursor) |
CursorLoader | AsyncTaskLoader的子類,它查詢ContentResolver然後傳回一個Cursor。這個類為查詢cursor以标準的方式實作了裝載器的協定,它的遊标查詢是通過AsyncTaskLoader在背景線程中執行,進而不會阻塞界面。使用這個裝載器是從一個ContentProvider異步加載資料的最好方式。相比之下,通過fragment或activity的API來執行一個被管理的查詢就不好了。 |
LoaderManager.LoaderCallbacks主要回調方法:
-
onCreateLoader() :初始化并傳回一個新的Loader
當你試圖去操作一個裝載器時(比如,通過initLoader()),會檢查是否指定ID的裝載器已經存在.如果它不存在,将會觸發LoaderManager.LoaderCallbacks 的方法onCreateLoader();
-
onLoadFinished():當一個裝載器完成了它的裝載過程後被調用
這個方法是在前面已建立的裝載器已經完成其加載過程後被調用.這個方法保證會在應用到裝載器上的資料被釋放之前被調用;
-
onLoaderReset() :當一個裝載器被重置而其資料無效時被調用
所謂Loader的重置,就是指Loader對象還保留,隻是清除Loader中的資料,是以onLoaderReset()方法相當于Loader的銷毀方法。是以在onLoaderReset()方法中會找到即将釋放的資料的引用,并移除這些引用。移除引用後,GC才可以清除這些資料。
當一個已建立的裝載器被重置進而使其資料無效時,此方法被調用.此回調使你能發現什麼時候資料将被釋放。你可以釋放對它的引用。
示例代碼:
3.1 CursorLoader異步加載資料(聯系人):
package com.noonecode.cursorloaderdemo;
import android.app.Activity;
import android.app.LoaderManager;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.support.v4.widget.SimpleCursorAdapter;
import android.widget.ListView;
/**
* 查詢手機聯系人,用CursorLoader
*
* CursorLoader一般用于查詢資料庫,ContentProvider執行耗時操作時使用
*
* @author NoOneCode
*
*/
public class MainActivity extends Activity implements LoaderCallbacks<Cursor> {
private ListView mLvShow;
private SimpleCursorAdapter adapter;
private LoaderManager loaderManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLvShow = (ListView) findViewById(R.id.lv_show);
adapter = new SimpleCursorAdapter(this, R.layout.contacts_item, null//
, new String[] { "_id", "display_name" }//
, new int[] { R.id.tv_id, R.id.tv_name }//
, SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
mLvShow.setAdapter(adapter);
// 擷取LoaderManager
loaderManager = getLoaderManager();
loaderManager.initLoader(, null, this);
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
if (id == ) {
return new CursorLoader(this, ContactsContract.RawContacts.CONTENT_URI,
new String[] { "_id", "display_name" }, null, null, "_id asc");
}
return null;
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
adapter.swapCursor(data);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
adapter.swapCursor(null);
}
}
3.2 AsyncTaskLoader異步加載資料(聯系人)
package com.noonecode.asynctaskloaderdemo;
import android.app.Activity;
import android.app.LoaderManager;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.AsyncTaskLoader;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Loader;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
public class MainActivity extends Activity implements LoaderCallbacks<Cursor> {
private ListView mLvShow;
private SimpleCursorAdapter adapter;
private LoaderManager loaderManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLvShow = (ListView) findViewById(R.id.lv_show);
adapter = new SimpleCursorAdapter(this, R.layout.contacts_item, null//
, new String[] { "_id", "display_name" }//
, new int[] { R.id.tv_id, R.id.tv_name }//
, SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
mLvShow.setAdapter(adapter);
loaderManager = getLoaderManager();
loaderManager.initLoader(, null, this);
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new MyLoader(this);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
adapter.swapCursor(data);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
adapter.swapCursor(null);
}
public static class MyLoader extends AsyncTaskLoader<Cursor> {
public MyLoader(Context context) {
super(context);
}
@Override
protected void onStartLoading() {
super.onStartLoading();
forceLoad();
}
@Override
public Cursor loadInBackground() {
ContentResolver resolver = getContext().getContentResolver();
Cursor cursor = resolver.query(ContactsContract.RawContacts.CONTENT_URI,
new String[] { "_id", "display_name" }, null, null, null);
return cursor;
}
@Override
protected void onStopLoading() {
super.onStopLoading();
}
}
}
注意
- 本例主要講解使用Loader異步加載資料過程,加載聯系人其他資訊不在本例研究範圍之内,如有需求,請檢視我的這篇文章 Android ContentResolver ContactsContract 擷取手機聯系人資訊
- 本例查詢的手機聯系人資訊需要讀取聯系人的權限:
本例不複雜,有源碼需求請留言!