我們編程的時候經常需要處理同步任務和異步任務,在Android里面存在一個特性,就是UI線程是不安全的線程。所謂UI線程不安全也就是我們的主線程(進程啟動的第一個線程)不能在線程外操作主線程的資源。因為主線程的資源沒有做同步處理。也就是我們一般說的線程同步問題。
我們做Android應用的時候,進程需要在一個子線程執行一些耗時的操作,例如下載、播放等。這種情況我們一般使用Handler和線程結合處理,子線程負責處理耗時操作,然后通知Handler處理UI更新。Handler和子線程結合處理適合對精度控制要求比較高或者任務耗時比較長或者比較反復的情況。除了Handler和線程結合使用,Android也為我們提供了另外一種選擇,也就是今天要說的AsyncTask。
AsyncTask內部也是使用了Handler和線程的模式,只是Google把它封裝好了。下面我們看看AsyncTask如何使用。
(PS:新建的QQ群,有興趣可以加入一起討論:Android群:322599434)
1、android.os.AsyncTask的定義
public abstract class AsyncTask<Params, Progress, Result>
- Params:輸入的參數
- Progress:更新的進度,一般用來更新UI的進度信息
- Result:是執行后的返回結果
這些參數都是泛型定義,所以我們可以定義自己的數據類型作為參數,另外如果不需要相關傳輸,可以傳入Void即可。
2、AsyncTask接口
//執行異步任務,啟動異步任務需要執行這個接口
public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }
//在execute()被調用后立即執行,可以做一些任務初始化
protected void onPreExecute() { }
//在onPreExecute()執行后執行,執行一些耗時操作,此方法將接收輸入參數和返回計算結果。
//在執行過程中可以調用publishProgress()來更新進度信息
protected abstract Result doInBackground(Params... params);
//在調用publishProgress(Progress... values)時,回調這個方法,用來更新進度信息
protected void onProgressUpdate(Progress... values)
{
}
//doInBackground執行完后,會回調此方法,用於更新界面信息
protected void onPostExecute(Result result) { }
上面是AsyncTask的一些重要接口和方法,可以看出大部分都是空方法還有就是虛函數。我們繼承AsyncTask的時候,一般都需要重寫上面的方法,方便我們執行相應的操作。
3、AsyncTask例子
下面是我編寫的一個使用AsyncTask下載圖片的例子,這個例子功能是利用AsyncTask下載一張圖片。
private class DownLoad extends AsyncTask<String, Integer, String> { //onPreExecute方法在execute()后執行 @Override protected void onPreExecute() { Log.i(TAG, "onPreExecute() enter"); mShowLogTextView.setText("onPreExecute。。。begin downLoad"); } //doInBackground方法內部執行后台任務,不能在里面更新UI,否則有異常。 @Override protected String doInBackground(String... params) { Log.i(TAG, "doInBackground(String... params) enter"); URL imageUrl=null; try { imageUrl=new URL(params[0]); } catch (MalformedURLException e) { e.printStackTrace(); Log.e(TAG, e.getMessage()); } try { //使用HttpURLConnection打開連接 HttpURLConnection urlConn=(HttpURLConnection)imageUrl.openConnection(); urlConn.setDoInput(true); urlConn.connect(); //將得到的數據轉化成InputStream InputStream is=urlConn.getInputStream(); //將InputStream轉換成Bitmap mDownLoadBtBitmap=BitmapFactory.decodeStream(is); is.close(); //不能在這里更新UI,否則有異常****** //mNetImageView.setImageBitmap(bitmap); }catch(IOException e) { Log.e(TAG,e.getMessage()); } return "ok"; } //onProgressUpdate方法用於更新進度信息 @Override protected void onProgressUpdate(Integer... progresses) { Log.i(TAG, "onProgressUpdate(Integer... progresses) enter"); mShowLogTextView.setText("onProgressUpdate Downloading..."); } //onPostExecute用於doInBackground執行完后,更新界面UI。 //result是doInBackground返回的結果 @Override protected void onPostExecute(String result) { Log.i(TAG, "onPostExecute(Result result) called"); mShowLogTextView.setText("Down load finish result="+result); mNetImageView.setImageBitmap(mDownLoadBtBitmap); } //onCancelled方法用於取消Task執行,更新UI @Override protected void onCancelled() { Log.i(TAG, "onCancelled() called"); mShowLogTextView.setText("onCancelled"); } }
上面是繼承了AsyncTask類,重寫了里面相關方法的之類,從上面可以看出AsyncTask主要的操作任務都是放到了doInBackground執行。然后onPostExecute最后更新結果。讓AsyncTask開始執行 的方法很簡單,只要調用execute並傳入相關參數即可。
public void onClick(View v) { if (v==mPlayMusicButton) { //傳入下載圖片的地址 mythou mDownLoad.execute("http://pic.desk.chinaz.com/file/10.11.10/7/jillxs40.jpg"); //mDownLoad.execute("http://www.baidu.com/img/bdlogo.gif"); } }
這里傳入的參數是作為doInBackground方法的參數,這里傳入圖片的URL,然后執行下載圖片操作。下面說說AsyncTask使用的時候需要注意的事情。
- AsyncTask的實例必須在UI線程中創建,並且在UI線程調用execute(Params... params)開始任務。
- 不要手動調用onPreExecute(),doInBackground(Params... params),onProgressUpdate(Progress... values), onPostExecute(Result result)等AsyncTask的回調函數。
- 不能在doInBackground(Params... params)中更改UI組件的信息。
- 一個任務實例只能執行一次,如果執行第二次將會拋出異常。
下面是這個例子執行效果:


AsyncTask的Demo代碼下載:點擊這里
Edited by mythou
原創博文,轉載請標明出處:http://www.cnblogs.com/mythou/p/3191174.html
