異步任務——AsyncTask
1. 用處:
將耗時操作放在非主線程中執行,既保證了Android單線程模型,也保證了程序的響應(不出現ANR)
AsyncTask在子線程中更新UI,封裝、簡化異步操作
2. AsyncTask <\Params, Progress, Result>
是一個抽象類,通常用於被繼承,繼承AsyncTask需要指定如下三個泛型參數:
Params:啓動任務時輸入參數的類型
Progress:後臺任務執行中返回進度值的類型
Result:後臺執行任務完成後返回結果的類型
注意:參數不是一定要使用, private class MyTask extends AsyncTask<\Void, Void, Void> { … }
3. 構建AsyncTask子類的回調方法:
onPreExecute:執行後太耗時操作前被調用,通常用戶完成一些初始化操作
doInBackground:必須重寫,異步執行後臺線程將要完成的任務
onProgressUpdate:在doInBackground()方法中調用publishProgress()方法更新任務的執行進度後,就會觸發該方法
onPostExecute:當doInBackground()完成後,系統自動調用該方法
只有doInBackground方法運行在子線程,其他幾個方法都運行在ui線程
ImageTest.java
該實例實現了網絡加載圖片。
public class ImageTest extends Activity {
private ImageView mImageView;
private ProgressBar mProgressBar;
private static String URL = "";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.image);
mImageView = (ImageView) findViewById(R.id.image);
mProgressBar = (ProgressBar) findViewById(R.id.progressbar);
new MyAsyncTask().execute(URL);
}
class MyAsyncTask extends AsyncTask<String, Void, Bitmap> {
@Override
protected void onPreExecute() {
super.onPreExecute();
mProgressBar.setVisibility(View.VISIBLE);
}
@Override
protected Bitmap doInBackground(String... params) { //傳遞進來一個可變長的數組
String url = params[0];
Bitmap bitmap = null;
URLConnection connection;
InputStream is;
try {
connection = new URL(url).openConnection();
is = connection.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
Thread.sleep(3000); //令線程睡眠3s以便觀察
bitmap = BitmapFactory.decodeStream(bis);
is.close();
bis.close();
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
mProgressBar.setVisibility(View.GONE);
mImageView.setImageBitmap(bitmap);
}
}
}
ProgressBarTest.java
該實例模擬了進度條的顯示。
AsyncTask底層是通過線程池實現的,一個線程必須結束後,另一個task纔會開始執行。因此,當希望結束當前task時,需要在Activity的onPause方法中添加cancel方法。然而默認情況下取消AsyncTask(設置mTask.cancel(true);)無法真正結束線程,必須在doInBackground和onProgressUpdate方法中結束循環或中斷方法。
public class ProgressBarTest extends Activity {
private ProgressBar mProgressBar;
private MyAsyncTask mTask;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.progressbar);
mProgressBar = (ProgressBar) findViewById(R.id.pg);
mTask = new MyAsyncTask();
mTask.execute();
}
@Override
protected void onPause() {
super.onPause();
if(mTask != null && mTask.getStatus() == Status.RUNNING) {
//cancel方法只是將對應的AsyncTask標記爲cancel狀態,並不是真正地取消線程的執行
mTask.cancel(true);
}
}
class MyAsyncTask extends AsyncTask<Void, Integer, Void> {
@Override
protected Void doInBackground(Void... params) {
//模擬進度更新
for (int i = 0; i < 100; i++) {
if (isCancelled()) {
break;
}
publishProgress(i); //將參數傳遞給onProgressUpdate
try {
Thread.sleep(300); //令線程睡眠300ms
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
if (isCancelled()) {
return;
}
//獲取進度更新值
mProgressBar.setProgress(values[0]);
}
}
}
AsyncTask注意事項
1. 必須在UI線程中創建AsyncTask的實例。即在MainActivity中初始化MyAsyncTask task = new MyAsyncTask();
2. 必須在UI線程中調用AsyncTask的execute()方法,即在MainActivity中調用task.execute()方法。
3. 重寫的四個方法是系統自動調用的,不應手動調用
4. 每個AsyncTask只能被執行一次,多次調用將會引發異常