Android AsyncTask詳解
在Google中Android API對AsyncTask解析:
AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
AsyncTask的使得適當的和易於使用的使用者介面執行緒。這個類允許執行後臺操作而無需操作執行緒和/或處理程式釋出在UI執行緒上的結果。
AsyncTask is designed to be a helper class around
and and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds
at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by thejava.util.concurrent
AsyncTask的設計是圍繞Thread和Handler一個輔助類,並不構成一個通用執行緒框架。AsyncTasks最好應採用短作業(幾秒鐘之最。)如果你需要保持執行很長一段時間的執行緒,我們強烈建議您使用,如提供的java.util.concurrent中pacakge的各種API遺囑執行人,的ThreadPoolExecutor和FutureTask。
An asynchronous task is defined by a computation that runs on a background thread and whose result is published on the UI thread. An asynchronous task
is defined by 3 generic types, called Params
Progress
andResult
, and 4 steps, calledonPreExecute
,doInBackground
, onProgressUpdate
andonPostExecute
.
非同步任務是由一個後臺執行緒,其結果公佈在UI執行緒上執行的計算確定。一個非同步任務由3泛型型別,稱為Params,進展和成效,以及4個步驟,稱為onPreExecute,doInBackground,onProgressUpdate和onPostExecute定義。
在Android實現非同步機制有兩種方式:分別是AsyncTask與Handler
AsyncTask實現原理
AsyncTask是Android提供的輕量級的非同步類,可以直接繼承AsyncTask,在類中實現非同步操作,並提供介面反饋當前執行的程度(可以通過介面實現UI進度更新),最後反饋執行結果給UI主執行緒。
優點:
1、簡單、快捷
2、過程可控
缺點:
1、在使用多個非同步操作和並需要UI變更時,該操作就變得複雜
Handler實現原理
在Handler非同步實現時,涉及到Handler、Looper、Message、Thread四個物件,實現非同步的流程是主執行緒啟動Thread(子執行緒)執行並生成Message-aLooper獲取Message並傳遞給Handler逐個獲取Looper中的Message,並進行UI變更。
優點:
1、結構清晰,功能定義明確
2、對於多個後臺任務是,簡單、清晰
缺點:
1、在單個後臺非同步處理時,顯得程式碼過多,結構過於複雜(相對性)。
總結:
AsyncTask比Handler更輕量級,更適用於簡單簡單的非同步處理。
Android中有Android和Handler都是為了不阻塞主執行緒(UI執行緒),且UI的更新只能在主執行緒中完成,所以非同步處理是不可避免的。
AsyncTask詳解:
Android為了降低開發難度,提供了AsyncTask,AsyncTask就是一個封裝過後的後臺任務類,既是非同步任務類。
AsyncTask是直接繼承Object,其位於android.os.AsyncTask,要使得AsyncTask工作,我們必須三個泛型引數,並重載幾個方法(至少一個)
AsyncTask定義了三個泛型引數:Params,Progress與Result
- Params啟動任務執行的輸入引數,比如:Http請求的URL
- Progress後臺執行任務的百分比
- Result後臺執行任務最終返回的結果,比如String
經常過載的兩個方法:
- doInBackground(Params…)後臺執行,比較耗時的操作都可以放在這裡,注意這裡不能直接操作UI。此方法在後臺執行,完成任務的主要工作,通常需要較長的時間,在執行過程中可以呼叫publicProgress(Progress…)來更新任務的進度。
- onPostExecute(Result) 相當於Handler的UI處理方式,在這裡可以使用doInBackground得到的結果處理操作UI。此方法在主執行緒執行,任務執行的結果作為此方法的引數返回
有必要的話,你還可以重寫以下的三個方法,但不是必須的:
- onProgressUpdate(Progress…) 可以使用進度條增加使用者的體驗度,此方法在主執行緒執行,用於顯示任務執行的進度
- onPreExecute()這裡是終端使用者呼叫Execute時的介面,當任務執行執行呼叫此方法,可以在這顯示進度對話方塊
- onCancelled() 使用者呼叫取消時,要做的操作
一個非同步任務的執行一般包括以下幾個步驟:
- execute(Params... params)執行一個非同步任務,我們需要在程式碼中呼叫此方法,觸發非同步任務的執行;呼叫UI執行緒上執行任務之前。這個步驟是通過示出在使用者介面的進度條通常用於設定任務
- onPreExecute()在執行execute(Params... params)後立即執行,一般用來在執行後臺任務前對UI做的一些標記;啟動一個進度對話方塊,向用戶顯示任務進度情況。
- doInBackground(Params…)在onPreExecute()完成後立即執行,用於執行較為費時的操作,此方法將接收輸入引數和返回計算結果,在執行過程中可以呼叫publicProgress(Progress…)來更新任務的進度
- onProgressUpdate(Progress…) 在呼叫publicProgress(Progress…)時,此方法被執行,直接將進度資訊更新在UI元件上
- onPostExecute(Result) 在後臺操作結束後,此方法將被呼叫,計算結果將作為引數傳遞到此方法中,直接將結果顯示在UI元件上
呼叫AsyncTask必須必須遵守的規則:
- AsyncTask例項必須在UI 執行緒中建立
- exeucte()方法必須在UI執行緒中呼叫
- 不要手動的呼叫doInBackground(Params…)、onPostExecute(Result) 、onProgressUpdate(Progress…) 、onPreExecute()這幾個方法。
- 該AsyncTask例項只能別調用一次,否則多次呼叫時將會出現異常
- 不能在doInBackground(Params…)方法中更改UI元件的資訊
實現一個簡單的例子,可以明確進度並且可以取消非同步操作的
佈局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:id="@+id/textView01"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<Button
android:id="@+id/button03"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="更新progressbar"
/>
</LinearLayout>
AsyncTask的繼承類
package com.sym.asynctaskdemo;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.os.AsyncTask;
import android.widget.TextView;
public class ProgressBarAsyncTask extends AsyncTask<Integer, Integer, String>{
private TextView textView;
private ProgressDialog progressBar;
private Context context;
public static boolean isrunning = false;
public ProgressBarAsyncTask(TextView textView, Context context) {
super();
this.textView = textView;
this.context = context;
}
/**
* 這裡的Integer引數對應AsyncTask中的第一個引數
* 這裡的String返回值對應AsyncTask的第三個引數
* 該方法並不執行在UI執行緒當中,主要用於非同步操作,所有在該方法中不能對UI當中的空間進行設定和修改
* 但是可以呼叫publishProgress方法觸發onProgressUpdate對UI進行操作
*/
@Override
protected String doInBackground(Integer... params) {
int i = 0;
if(this.isCancelled()){
return null;
}else{
for (i = 2; i <= 100; i+=2) {
try {
publishProgress(i);//這個必須執行,否則不會更新
Thread.sleep(1000);
} catch (InterruptedException e) {
return null;//這裡必須返回空,否則無法停止後臺的操作
}
}
return params[0].intValue() + "";
}
}
/**
* 這裡的String引數對應AsyncTask中的第三個引數(也就是接收doInBackground的返回值)
* 在doInBackground方法執行結束之後在執行,並且執行在UI執行緒當中 可以對UI空間進行設定
*/
@Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
textView.setText("非同步操作執行結束" + result);
progressBar.setTitle("非同步操作執行結束");
progressBar.cancel();
isrunning = true;
}
//該方法執行在UI執行緒當中,並且執行在UI執行緒當中 可以對UI空間進行設定
@SuppressWarnings("deprecation")
@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
textView.setText("開始執行非同步執行緒");
progressBar = new ProgressDialog(context);
progressBar.setTitle("開始執行非同步執行緒");
progressBar.setMessage("in progress......");
progressBar.setButton("取消", new android.content.DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
if(!isrunning){//判斷標識
ProgressBarAsyncTask.this.cancel(true);
}
}
});
progressBar.setCancelable(true);
progressBar.setOnCancelListener(new OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
// TODO Auto-generated method stub
if(!isrunning){//判斷標識
ProgressBarAsyncTask.this.cancel(true);
}
}
});
progressBar.setIndeterminate(false);//設定Indeterminate為false,可以明確進度
progressBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressBar.setMax(100);
progressBar.setCanceledOnTouchOutside(false);
progressBar.show();
}
/**
* 這裡的Intege引數對應AsyncTask中的第二個引數
* 在doInBackground方法當中,,每次呼叫publishProgress方法都會觸發onProgressUpdate執行
* onProgressUpdate是在UI執行緒中執行,所有可以對UI空間進行操作
*/
@Override
protected void onProgressUpdate(Integer... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
if(this.isCancelled()) return;//判斷AsyncTask是否取消,如果是,則停止更新;否則繼續
int vlaue = values[0];
progressBar.setProgress(vlaue);
}
@Override
protected void onCancelled() {
// TODO Auto-generated method stub
super.onCancelled();
isrunning = true;
progressBar.setTitle("非同步操作暫停");
textView.setText("非同步操作暫停");
progressBar.setProgress(0);
}
}
Activity主類:
package com.sym.asynctaskdemo; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; public class MainActivity extends Activity { private Button button; private TextView textView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button = (Button)findViewById(R.id.button03); textView = (TextView)findViewById(R.id.textView01); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { ProgressBarAsyncTask asyncTask = new ProgressBarAsyncTask(textView, MainActivity.this); asyncTask.execute(2000); ProgressBarAsyncTask.isrunning = false;//修改標識 } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } }
執行結果圖: