簡介
不管是在Android應用開發還是Android平台開發中,異步處理通常是最基本的coding要求。如果你還在主線程中寫一些數據庫,網絡請求,讀寫本地文件等操作的話那說明你還不是一個合格的Android程序員。
通常情況下我們使用的最多的Android異步處理方法是AsyncTask
和Handler
,但今天要給大家帶來的是大家不常使用的AsyncTaskLoader
的使用方法。
AsyncTaskLoader
從名字看出來它似乎和AsyncTask
有關系,看一下Google官方是怎么給AsyncTaskLoader
下定義的:
Abstract Loader that provides an AsyncTask to do the work
果然是樣,AsyncTaskLoader
是使用一個AsyncTask
來進行異步處理的。那么問題來了,既然都有了AsyncTask
了為什么還要搞出來一個AsyncTaskLoader
呢?
其實AsyncTaskLoader
遠沒有大家想的那么簡單。說的通俗一點,如果把AsyncTask
比作一台烤面包機的話,那么AsyncTaskLoader
就是操作烤面包機的面包師。AsyncTask
如同烤面包機接受命令完成面包的烤制任務,一旦任務完成它就停止了工作。然而AsyncTaskLoader
如同面包師一樣要根據顧客的需求來使用烤面包機。顧客會不停的光顧,那么面包師就會不停的使用烤面包機烤面包。
具體事例
下面我們就通過烤面包機和面包師的例子來演示一下AsyncTaskLoader
的使用方法。
首先肯定少不了面包師(Baker):
package com.example.asyncloaderdemo;
import java.util.ArrayList;
import java.util.List;
import android.content.AsyncTaskLoader;
import android.content.Context;
public class Baker extends AsyncTaskLoader<List<Bread>> {
// 用於查詢當前需要多少個面包
BakeryCallback mCallback;
//面包房回調,用於獲得當面面包需求量
interface BakeryCallback {
int getNeededBreads();
}
public Baker(Context context, BakeryCallback callback) {
super(context);
mCallback = callback;
}
@Override
public List<Bread> loadInBackground() {
List<Bread> breads = new ArrayList<Bread>();
//獲得當前需要做的面包
int needs = mCallback.getNeededBreads();
for (int i = 0; i < needs; i++) {
//制作面包,耗時操作
breads.add(new Bread());
}
//面包制作完成
return breads;
}
@Override
public void deliverResult(List<Bread> data) {
super.deliverResult(data);
}
@Override
protected void onStartLoading() {
forceLoad();
}
@Override
protected void onStopLoading() {
cancelLoad();
}
@Override
protected void onReset() {
super.onReset();
}
}
面包師有了,面包房(Bakery)也不能少
package com.example.asyncloaderdemo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
public class Bakery extends BroadcastReceiver {
final Baker mBaker;
public static String CUSTOMER_ACTION = "com.example.asyncloaderdemo.new_customer" ;
public Bakery(Baker baker) {
mBaker = baker;
IntentFilter filter = new IntentFilter(CUSTOMER_ACTION);
baker.getContext().registerReceiver(this, filter);
}
@Override public void onReceive(Context context, Intent intent) {
//通知面包師來客人了,要做面包了。
mBaker.onContentChanged();
}
}
面包房和面包師都有了,還缺一個場景(MainActivity)
package com.example.asyncloaderdemo;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import com.example.asyncloaderdemo.Baker.BakeryCallback;
import android.support.v7.app.ActionBarActivity;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.Intent;
import android.content.Loader;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends ActionBarActivity {
private LoaderCallbacks<List<Bread>> mCallbacks;
//面包房
private Bakery mBakery;
//面包師
private Baker mBaker;
//面包需求量
private int mNeededBreads;
//唯一標識
private final int mLoaderId = 42;
private BakeryCallback mBreadCallback = new BakeryCallback() {
@Override
public int getNeededBreads() {
return mNeededBreads;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mNeededBreads = 0;
mBaker = new Baker(this, mBreadCallback);
mBakery = new Bakery(mBaker);
mCallbacks = new LoaderCallbacks<List<Bread>>() {
@Override
public Loader<List<Bread>> onCreateLoader(int id, Bundle args) {
if (mBaker == null) {
mBaker = new Baker(MainActivity.this, mBreadCallback);
}
return mBaker;
}
@Override
public void onLoadFinished(Loader<List<Bread>> loader, List<Bread> data) {
mNeededBreads = 0 ;
//面包師完成面包烤制
Log.d("scott", "sell " + data.size() + " breads") ;
}
@Override
public void onLoaderReset(Loader<List<Bread>> loader) {
}
};
//面包師開始工作
getLoaderManager().restartLoader(mLoaderId, null, mCallbacks);
//顧客開始上門
mockCustomer();
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mBakery);
}
//模擬源源不斷的顧客需求
private void mockCustomer(){
new Thread(new Runnable() {
@Override
public void run() {
while(true){
try {
Thread.sleep(3000);
Random random = new Random();
mNeededBreads =random.nextInt(10);
Intent intent = new Intent(Bakery.CUSTOMER_ACTION);
sendBroadcast(intent);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
接下來我們來看一下程序運行結果:
通過上圖並結合代碼可以看出來每隔三秒就會有新的顧客上門,顧客上門后面包房通知面包師需要做面吧哦了,接着面包師就會在后台不停的開始使用面包機(AsyncTask)做面包。
總結
說到這里可能有些同學有疑問了,我怎么從頭到尾都沒有開到AsyncTask
的影子呢?你當然看不到,這就是AsyncTaskLoader
設計精妙之處,它做到了讓你唯一需要考慮的就是烤面包(異步處理)這個事物邏輯,而不需要考慮異步處理本身的實現上。同時這也充分體現了設計模式中的單一職責
和最少知道
原則。
使用場景
AsyncTaskLoader
一般使用在數據源處於不斷更新並且請求刷新數據源是個耗時操作的情況下還需要UI去同步更新相關數據的場景(這句話怎么這么拗口)。