1、引言
在Android中,幾乎完全采用了Java的線程機制,由于Android的特性,主線程只處理和界面相關的事情,子線程處理耗時操作。Android中扮演線程角色的有Thread、AsyncTask、IntentService和HandlerThread。對于AsyncTask來說,底層用到了線程池,對于IntentService和HandlerThread,底層用到了線程。
2、AsyncTask
AsyncTask是一個抽象的泛型類,它提供了Params、Progress和Result這三個泛型參數。
public abstract class AsyncTask<Params, Progress, Result>
其中Params表示參數類型,Progress表示后臺任務的執行進度的類型,Result表示后臺任務返回結果的類型。并且提供了五個核心的方法。
@MainThread
protected void onPreExecute() {
}
此方法有個@MainThread注解,表示在主線程執行,在異步任務執行之前,此方法會被調用,一般可以做一些準備工作。
@WorkerThread
protected abstract Result doInBackground(Params... params);
此方法有個@WorkerThread注解,表示在工作(子)線程執行,用于執行異步任務,params參數表示異步任務的輸入參數,可調用publishProgress方法來更新任務進度,publishProgress會調用onProgressUpdate方法。并且此方法需要返回計算結果給onPostExecute方法。
@MainThread
protected void onPostExecute(Result result) {
}
在主線程中執行,在異步任務執行后,此方法會被調用,result是后臺任務的返回值。
@MainThread
protected void onProgressUpdate(Progress... values) {
}
在主線程中執行,后臺任務的執行進度發生變化時,此方法會被調用。
@MainThread
protected void onCancelled(Result result) {
onCancelled();
}
在主線程中執行,當異步任務被取消是,此方法會被調用,而onPostExecute則不會被調用。
class MyTask extends AsyncTask<String, Integer, String> {
@Override
protected void onPreExecute() {
Log.i(TAG, "onPreExecute() called");
textView.setText("loading...");
}
@Override
protected String doInBackground(String... strings) {
Log.i(TAG, "doInBackground(Params... params) called");
try {
OkHttpClient client = new OkHttpClient.Builder().readTimeout(5, TimeUnit.SECONDS).build();
Request request = new Request.Builder()
.url(strings[0])
.get()
.build();
Call call = client.newCall(request);
Response response = call.execute();
if (response.code() == 200) {
InputStream is = response.body().byteStream();
long total = response.body().contentLength();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int count = 0;
int length = 0;
while ((length = is.read(buf)) != -1) {
baos.write(buf, 0, length);
count += length;
//調用publishProgress公布進度,最后onProgressUpdate方法將被執行
publishProgress((int) (count * 1.0f / total * 100));
//為了演示進度,休眠500毫秒
Thread.sleep(500);
}
return new String(baos.toByteArray(), "utf8");
}
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
return null;
}
//onProgressUpdate方法用于更新進度信息
@Override
protected void onProgressUpdate(Integer... progresses) {
Log.i(TAG, "onProgressUpdate(Progress... progresses) called");
progressBar.setProgress(progresses[0]);
textView.setText("loading..." + progresses[0] + "%");
}
//onPostExecute方法用于在執行完后臺任務后更新UI,顯示結果
@Override
protected void onPostExecute(String result) {
Log.i(TAG, "onPostExecute(Result result) called");
textView.setText(result);
execute.setEnabled(true);
cancel.setEnabled(false);
}
//onCancelled方法用于在取消執行中的任務時更改UI
@Override
protected void onCancelled() {
Log.i(TAG, "onCancelled() called");
textView.setText("cancelled");
progressBar.setProgress(0);
execute.setEnabled(true);
cancel.setEnabled(false);
}
}
上面代碼中,實現一個具體的AsyncTask類,主要模擬get請求,并且更新progress。
AsyncTask使用限制
- 類必須在主線程中加載
- 對象必須在主線程中創建
- execute方法必須在UI線程調用
- 不要在程序中直接調用onPreExecute、onPostExecute、doInBackground、onProgressUpdate方法
- 一個AsyncTask對象只能執行一次,多次執行會報運行時異常。
3、HandlerThread
HandlerThread本質上是一個線程類,它繼承了Thread,并且可以創建一個帶有looper的線程,進行looper循環;looper對象可以用于創建Handler類來進行來進行調度,必須調用start()方法,Thread會先調用run方法來創建Looper對象。源碼如下:
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
創建HandlerThread很簡單,它有兩個構造函數,第一個構造函數只需要傳遞線程名稱即可,第二構造函數除了線程名稱,還需要設置優先級的功能
HandlerThread thread = new HandlerThread("downImage");
thread.start();
HandlerThread thread = new HandlerThread("downImage", Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
需要注意的是,HandlerThread的run是一個無限循環,因此明確不需要它時,需要調用quit和quitSafely方法來終止線程的執行。
4、IntentService
IntentService繼承了Service,并且它是一個抽象類,因此必須創建它的子類才能使用IntentService。它用于執行后臺耗時的任務,執行完會自動停止。它擁有較高的優先級,不易被系統殺死(繼承自Service的緣故),因此比較適合執行一些高優先級的異步任務。
IntentService其實還是由HandlerThread和Handler實現的。
@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);
}
onCreate中創建了一個HandlerThread ,在通過HandlerThread創建了一個Handler。startService后,最終會調用onStart方法。
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
從上面可以看出,mServiceHandler 發送的消息最終都會在HandlerThread 執行,會將Intent的對象傳遞給onHandleIntent抽象方法(需要子類實現)處理。onHandleIntent處理完之后會調用stopSelf(int startId)方法嘗試停止服務,而不是stopSelf()來立即停止服務。下面創建一個示例看看它是怎樣實現的。
public class DownLoadService extends IntentService {
public DownLoadService(String name) {
super(name);
}
@Override
protected void onHandleIntent(@androidx.annotation.Nullable @Nullable Intent intent) {
String url = intent.getStringExtra("url");
Bitmap bitmap = dowload(url);
// 保存邏輯處理
}
}
啟動跟Service一樣
Intent intent = new Intent(this, DownLoadService.class);
startService(intent);