首先是AsyncTask
這是一個用於異步處理數據的線程操作類。由於Android中存在UI線程的概念,只有在UI線程中才能對View(肉眼可見的地方)進行修改和調整。UI線程中是不能做一些耗時地操作的,比如說訪問網絡(http請求)、從SD卡讀寫數據(I/O操作)亦或者是比較複雜的數據運算,這些都是不能放在UI線程中進行的(會導致ANR異常)。
爲了解決這個問題,Android系統提供了這個異步操作類。(以下是部分代碼)
public abstract class AsyncTask<Params, Progress, Result> {
/**
* Override this method to perform a computation on a background thread. The
* specified parameters are the parameters passed to {@link #execute}
* by the caller of this task.
*
* This method can call {@link #publishProgress} to publish updates
* on the UI thread.
*
* @param params The parameters of the task.
*
* @return A result, defined by the subclass of this task.
*
* @see #onPreExecute()
* @see #onPostExecute
* @see #publishProgress
*/
@WorkerThread
protected abstract Result doInBackground(Params... params);
/**
* <p>Runs on the UI thread after {@link #doInBackground}. The
* specified result is the value returned by {@link #doInBackground}.</p>
*
* <p>This method won't be invoked if the task was cancelled.</p>
*
* @param result The result of the operation computed by {@link #doInBackground}.
*
* @see #onPreExecute
* @see #doInBackground
* @see #onCancelled(Object)
*/
@SuppressWarnings({"UnusedDeclaration"})
@MainThread
protected void onPostExecute(Result result) {
}
}
這裏注意到doInBackground方法上的註解@WorkerThread和onPostExecute方法上的@MainThread,這兩個註解就提示了我們,這兩個方法是運行不同的線程上的。
通常我們會把耗時操作放在doInBackground方法中,然後將執行結果Result返回。從上面的註釋中我們可以看到onPostExecute會跟在doInBackground之後執行,不同的是onPostExecute方法是在UI線程中執行的,在這裏我們對View(肉眼可見的界面)進行操作了。還有onPostExecute方法中有一個Result參數,這個參數就是doInBackground方法中返回的Result,我們可以根據這個Result做相關的UI操作。
例子:
public class DecodeBitmapTask extends AsyncTask<String, Integer, Bitmap> {
private ImageView imageView;
public VideoShotTask(ImageView imageView) {
this.imageView = imageView;
}
@Override
protected Bitmap doInBackground(String... params) {
String sourcePath = params[0];
Bitmap bitmap = BitmapFactory.decodeFile(sourcePath);
return bitmap;
}
@Override
protected void onPostExecute(Bitmap result) {
if (imageView != null && result != null) {
imageView.setImageBitmap(result);
}
this.cancel(true);//執行完成之後可以取消任務
}
}
這就是一個從sd卡中加載圖片,並繪製到ImageView上的過程。
使用上面這個類的方法也很簡單
DecodeBitmapTask dbt = new DecodeBitmap(傳入一個ImageView);
dbt.execute("傳入一個圖片資源路徑");
這樣就可以實現工作線程(子線程)與UI線程(主線程)之間的配合啦。
ps:當然AsyncTask的功能不止於此,我這裏只是做個簡單的例子。
HandlerThread
就像它的名字一樣,它是由Handler和Thread有機結合起來的一個類。它區別於我們直接通過new Thread的方式創建線程,HandlerThread創建的線程是可以反覆重用的,也就減少了因爲new新的實例而導致的內存開銷。而且它Handler中功能,使得我們對線程的使用更加的靈活。
//首先創建一個HandlerThread對象
HandlerThread mHT = new HandlerThread("傳入線程的名字");
//隨後啓動線程
mHT.start();
//根據HandlerThread的Looper來創建一個Handler對象
Handler workHandler = new Handler( mHT.getLooper() ) {
@Override
public void handleMessage(Message msg) {
//這裏是運行在工作線程中,而不是UI線程
switch(msg.what){
case 2:
//do something。。。
break;
}
}
});
//這裏通過傳統的Handler發送消息的方式,來觸發線程
Message msg = Message.obtain();
msg.what = 2; //消息的標識
msg.obj = "B"; // 消息的存放
workHandler.sendMessage(msg);
// 最後不需要用的時候,結束線程,即停止線程的消息循環
mHT.quit();
如此一來,我們就可以通過Handler來操作、執行工作線程。這樣做的好處就是減少了我們new Thread的操作,這樣可以大大的減少內存泄漏的風險和過多的內存開銷。
IntentService
這是一個Service與HandlerThread的結合體。首先我們知道Service是android的四大組件之一,長期在後臺處理數據。但是它並不是一個線程,如果在Service中執行耗時操作就會產生ANR異常,那麼當一個Service需要處理比較多的耗時任務時,就需要單獨開啓一個工作線程來完成。IntentService就是基於這種應用場景而誕生的。
IntentService繼承自Service
//IntentService源碼節選
@Override
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
/**
* This method is invoked on the worker thread with a request to process.
* Only one Intent is processed at a time, but the processing happens on a
* worker thread that runs independently from other application logic.
* So, if this code takes a long time, it will hold up other requests to
* the same IntentService, but it will not hold up anything else.
* When all requests have been handled, the IntentService stops itself,
* so you should not call {@link #stopSelf}.
*
* @param intent The value passed to {@link
* android.content.Context#startService(Intent)}.
* This may be null if the service is being restarted after
* its process has gone away; see
* {@link android.app.Service#onStartCommand}
* for details.
*/
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
在它的onCreate方法中可以看到,它的內部其實就是通過封裝HandlerThread來實現工作線程的。當我們要使用它時,需要先繼承IntentService,然後實現它的抽象方法onHandleIntent方法。(由於它也是一個Service,別忘了在AndroidManifest中配置它)
public class TestIntentService extends IntentService {
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public TestIntentService(String name) {
super(name);
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
//do something。。。
//此時也是運行在工作線程(子線程)中哦
//Intent用於傳遞我們需要的數據,每一次通過startService方法觸發,都會按順序執行,不會無序執行
}
}
在我們使用這個IntentService的時候,就是這樣:
Intent intent = new Intent(MainActivity.this, TestIntentService.class);
startService(intent);//intent當中記得要存放你需要傳遞的參數哦
就像我上面的註釋中說的那樣,每次startService,都會按照順序去執行,並不會像我們new Thread那樣,順序完全隨機。並且它與Service不同的地方在於,它不需要手動執行stopService方法來終止服務。因爲在它的源碼中:
//在IntentService的內部類中可以看出來
//每一次執行完任務,都會自己調用stopSelf方法
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}