今天學到了這個Loader,淺談一下自己的看法: 1.定義 Loader是一個載入器,可以用來它訪問數據,可以看做訪問數據的機器(好比挖掘機)。裝再器從android3.0開始引進,它使得在activity或fragment中非同步載入數據變得簡單。 具有如下特別: 1)它們對每個Activity和F ...
今天學到了這個Loader,淺談一下自己的看法:
1.定義
Loader是一個載入器,可以用來它訪問數據,可以看做訪問數據的機器(好比挖掘機)。裝再器從android3.0開始引進,它使得在activity或fragment中非同步載入數據變得簡單。
具有如下特別:
1)它們對每個Activity和Fragment都有效
2)它們提供了非同步載入數據的能力
3)它擁有一個數據改變通知機制,當數據源做出改變是會及時通知。當Cursor發生變化時,會自動載入數據,因此不需要重新進行數據查詢
解釋一下為什麼會有非同步載入數據的能力:
final class LoadTask extends ModernAsyncTask<Void, Void, D> implements Runnable {
private final CountDownLatch mDone = new CountDownLatch(1);
// Set to true to indicate that the task has been posted to a handler for
// execution at a later time. Used to throttle updates.
boolean waiting;
/* Runs on a worker thread */
@Override
protected D doInBackground(Void... params) {
if (DEBUG) Log.v(TAG, this + " >>> doInBackground");
try {
D data = AsyncTaskLoader.this.onLoadInBackground();
if (DEBUG) Log.v(TAG, this + " <<< doInBackground");
return data;
} catch (OperationCanceledException ex) {
if (!isCancelled()) {
// onLoadInBackground threw a canceled exception spuriously.
// This is problematic because it means that the LoaderManager did not
// cancel the Loader itself and still expects to receive a result.
// Additionally, the Loader's own state will not have been updated to
// reflect the fact that the task was being canceled.
// So we treat this case as an unhandled exception.
throw ex;
}
if (DEBUG) Log.v(TAG, this + " <<< doInBackground (was canceled)", ex);
return null;
}
}
protected D onLoadInBackground() {
return loadInBackground();
}
public abstract D loadInBackground();
這是AsyncTaskLoader底層代碼實現。可以看出,在AsyncTaskLoader中創建一個final修飾的內部類,實現非同步任務。封裝了一個抽象方法loadInBackground(),在子類繼承時,實現各自的實現方式。
2.作用
用來載入數據,訪問資料庫(系統自帶的資料庫,自定義資料庫)。當然訪問資料庫,我們可以使用ContentResolver通過query()訪問資料庫,得到一個Cursor對象,遍歷這個對象就可以拿到我們想要的數據。但Loader的作用比ContentResolver更簡便更快捷。
3.用法(使用裝載器時設計到的類和方法)
LoaderManager:本身是一個抽象類。關聯到每一個Activity或Fragment,管理一個或多個裝載器的實例。這幫助一個應用管理那些與Activity或Fragment的聲明周期相關的長時間運行的操作。最常見的方式是與一個CursorLoader一起使用,然而應用是可以隨便寫它們自己的載入器從而載入其他類型的數據。
LoaderManager.LoaderCallBack<D>:本身是一個介面。一個用於客戶端與LoaderManager交互的回調介面。如:你可以使用onCreateLoader()創建一個Loader載入器
Loader:本身是一個抽象類。一個執行非同步數據載入的抽象類。它是載入器的基類,你可以使用典型的CursorLoader,但是你也可以使用自定義的Loader(創建一個類extends AsyncTaskLoader),它們將監試它們的數據源並且在數據改變是發送新的結果。
AsyncTaskLoader:本身是一個抽象類,提供一個AsyncTask來執行非同步載入工作(工作在子線程,進行耗時操作)。
CursorLoader:AsyncTaskLoader的實現類。
4.我自己寫的一個demo訪問手機聯繫人
package com.yz.searchcontacts;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.SearchView;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor> {
private ListView lv_contacts;
private SearchView msv_name;
private static ContentResolver mResolver;
private SimpleCursorAdapter mAdapter;
private LoaderManager manager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//獲取控制項
msv_name = (SearchView) findViewById(R.id.sv_name);
lv_contacts = (ListView) findViewById(R.id.list_item);
//創建適配器
mAdapter = new SimpleCursorAdapter(this, R.layout.list_item,null,new String[]{"_id","display_name"},new int[]{R.id.tv_id,R.id.tv_name},SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
lv_contacts.setAdapter(mAdapter);
//創建loader載入器,並初始化
manager = getSupportLoaderManager();
manager.initLoader(1,null,this);
//獲取ContentResolver
mResolver = getContentResolver();
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new MyLoader(this,args);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
mAdapter.swapCursor(data);
//為SearchView設置監聽
msv_name.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
Bundle args = new Bundle();
args.putString("name",newText);
manager.restartLoader(1,args,MainActivity.this);
return true;
}
});
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
mAdapter.swapCursor(null);
}
//自定義Loader
static class MyLoader extends AsyncTaskLoader<Cursor>
{
private Bundle args;
public MyLoader(Context context,Bundle args) {
super(context);
this.args = args;
}
@Override
protected void onStartLoading() {
super.onStartLoading();
//強制載入
forceLoad();
}
@Override
public Cursor loadInBackground() {
//進行耗時操作
Uri uri = ContactsContract.RawContacts.CONTENT_URI;
if (args != null) {
Cursor cursor = mResolver.query(uri, new String[]{"_id", "display_name"}, "display_name like ?", new String[]{"%" + args.getString("name") + "%"}, null);
return cursor;
}else
{
Cursor cursor = mResolver.query(uri, new String[]{"_id", "display_name"}, null, null, null);
return cursor;
}
}
}
}在這個簡單的小程式里有幾個我犯的小問題,提醒一下:
1)包的一致性
2)
protected void onStartLoading() {
super.onStartLoading();
//強制載入
forceLoad();
}