天天看點

使用Android AsyncTask異步線程

本文位址:http://blog.csdn.net/csheng1204/article/details/7233863 轉載請注明,謝謝~

首先聲明一下,本人是一個隻學了幾個月Android的新手,如有說得不好,請勿拍磚~~歡迎留言交流。

參考官方文檔和老外文章:(需要目田上網)

1、Multithreading For Performance

2、Painless threading

另外,關于為什麼一開始就講線程問題,有必要做個說明:

1、Android是單線程UI模型,是以假如不另外開辟線程做一些下載下傳圖檔、擷取網絡内容的的操作,會使UI給使用者一種“很卡”的感覺;

2、假如不引入多線程,很容易導緻Application Not Responding 也就是ANR,應用程式無響應,在手機上面一般表現為彈出一個警告視窗,“強制關閉”、“Force Close”這種惡心的問題;

3、Android本身提供一個封裝好的異步線程類叫AsyncTask,為我們管理線程起到很好的作用。

AsyncTask<Params, Progress, Result>

用法:

    必須繼承AsyncTask并重寫至少一個方法 doInBackground(Params...),經常使用的是也重寫第二個方法 onPostExecute(Result)

參數:

  1. Params, 開始任務前傳入參數,注意的是,可變長輸入,可以一次性啟動執行多個下載下傳任務,例如傳入一組String[];
  2. Progress,在背景任務計算時,向外釋出程序的機關,一般是Int或者Double或者其他;
  3. Result,背景任務計算結束後,傳回的結果

    注意以上三個參數皆可為空,隻需要傳入AsyncTask<Void,Void,Void>即可。

程序4部曲:(其實還有1個~)

  1. onPreExecute(),在UI線程調用,然後立刻被執行。這個過程一般用來做一些初始化操作,例如顯示出一個ProgressBar提示使用者任務已經在執行中、例如讓啟動任務的Button變為Disabled,防止多次執行;
  2. doInBackground(Params...),當onPreExecute()執行完畢,會立刻在背景線程調用。這個過程一般用來做一些比較耗時的操作,如計算PI(當然沒人這麼無聊吧~)、例如下載下傳網絡圖檔,結果将會傳給最後一個過程onPostExecute(Result)。當然為了使你的程式更加友好,可以顯示進度,而具體進度如何,就是通過在這個過程調用 publishProgress(Progress...) 來向外(指UI線程)釋出程序。
  3. onProgressUpdate(Progress...),當 publishProgress(Progress...)被調用時,會在UI線程調用此方法。一般是用來提示使用者進度,例如用在Notification上面顯示下載下傳進度條;
  4. onPostExecute(Result),當任務結束時在UI線程調用,傳入參數為doInBackground()的結果~~
  5. onCancelled(),在AsyncTask的cancel()方法被調用時觸發調用。

以下是一個自己寫的Demo,有一個按鈕,按鈕啟動異步任務下載下傳CSDN logo并顯示出來

<注意:以下屬性match_parent須在Android2.2之後才可以支援,效果同Android2.1及之前的fill_parent>

  AsyncTaskDemoActivity.java [java] view plain copy print ?

  1. package com.csheng.asynctask;  
  2. import java.io.InputStream;  
  3. import java.net.URL;  
  4. import java.net.URLConnection;  
  5. import android.app.Activity;  
  6. import android.graphics.Bitmap;  
  7. import android.graphics.BitmapFactory;  
  8. import android.os.AsyncTask;  
  9. import android.os.Bundle;  
  10. import android.view.View;  
  11. import android.view.View.OnClickListener;  
  12. import android.widget.Button;  
  13. import android.widget.ImageView;  
  14. public class AsyncTaskDemoActivity extends Activity {  
  15.     public static final String TAG = "AsyncTaskDemoActivity";  
  16.     private Button downloadBtn = null;  
  17.     private ImageView logoIv = null;  
  18.     private final String LOGO_URL = "http://csdnimg.cn/www/images/csdnindex_logo.gif";  
  19.     @Override  
  20.     public void onCreate(Bundle savedInstanceState) {  
  21.         super.onCreate(savedInstanceState);  
  22.         setContentView(R.layout.main);  
  23.         findViews();  
  24.     }  
  25.     private void findViews() {  
  26.         downloadBtn = (Button) findViewById(R.id.downloadBtn);  
  27.         logoIv = (ImageView) findViewById(R.id.logoIv);  
  28.         downloadBtn.setOnClickListener(new OnClickListener() {  
  29.             @Override  
  30.             public void onClick(View v) {  
  31.                 new DownloadAsyncTask().execute(LOGO_URL);// 啟動匿名任務  
  32.             }  
  33.         });  
  34.     }  
  35.     private class DownloadAsyncTask extends AsyncTask<String, Void, Bitmap> {  
  36.         @Override  
  37.         protected Bitmap doInBackground(String... params) {  
  38.             final String urlStr = params[0];// 取出execute所傳入參數  
  39.             URL url = null;  
  40.             try {  
  41.                 url = new URL(urlStr);  
  42.                 final URLConnection connection = url.openConnection();  
  43.                 final InputStream inputStream = connection.getInputStream();  
  44.                 final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);  
  45.                 if (bitmap != null) {  
  46.                     return bitmap;// 交給onPostExecute()處理  
  47.                 }  
  48.             } catch (Exception e) {  
  49.                 e.printStackTrace();  
  50.             }  
  51.             return null;  
  52.         }  
  53.         @Override  
  54.         protected void onPostExecute(Bitmap result) {  
  55.             if (result != null) {  
  56.                 logoIv.setImageBitmap(result);// 取出doInBackground()的計算結果  
  57.             }  
  58.             downloadBtn.setEnabled(true);  
  59.             super.onPostExecute(result);  
  60.         }  
  61.         @Override  
  62.         protected void onPreExecute() {  
  63.             downloadBtn.setEnabled(false);// 在整個異步下載下傳期間,不允許重新啟動下載下傳任務  
  64.             super.onPreExecute();  
  65.         }  
  66.     }  
  67. }  

main.xml

[html] view plain copy print ?

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent" >  
  5.     <Button  
  6.         android:id="@+id/downloadBtn"  
  7.         android:layout_width="wrap_content"  
  8.         android:layout_height="wrap_content"  
  9.         android:layout_centerHorizontal="true"  
  10.         android:text="@string/downloadText" />  
  11.     <!-- 圖檔放置于按鈕下方 -->  
  12.     <ImageView  
  13.         android:id="@+id/logoIv"  
  14.         android:layout_width="wrap_content"  
  15.         android:layout_height="wrap_content"  
  16.         android:layout_below="@+id/downloadBtn"  
  17.         android:layout_centerHorizontal="true"  
  18.         android:contentDescription="@string/contentDescription" />  
  19. </RelativeLayout>  

strings.xml [html] view plain copy print ?

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.     <string name="app_name">AsyncTaskDemo</string>  
  4.     <string name="downloadText">下載下傳圖檔</string>  
  5.     <string name="contentDescription">這是一張圖檔</string>  
  6.     <string name="startDownloadToast">開始下載下傳圖檔</string>  
  7.     <string name="setImageToast">設定圖檔資源</string>  
  8. </resources>  

對了,還有一個Manifest檔案,别忘了添加網絡權限

AndroidManifest.xml

[html] view plain copy print ?

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="com.csheng.asynctask"  
  4.     android:versionCode="1"  
  5.     android:versionName="1.0" >  
  6.     <uses-sdk android:minSdkVersion="8" />  
  7.     <uses-permission android:name="android.permission.INTERNET" />  
  8.     <application  
  9.         android:icon="@drawable/ic_launcher"  
  10.         android:label="@string/app_name" >  
  11.         <activity  
  12.             android:name=".AsyncTaskDemoActivity"  
  13.             android:label="@string/app_name" >  
  14.             <intent-filter>  
  15.                 <action android:name="android.intent.action.MAIN" />  
  16.                 <category android:name="android.intent.category.LAUNCHER" />  
  17.             </intent-filter>  
  18.         </activity>  
  19.     </application>  
  20. </manifest>  

再來個圖檔刺激下~~效果如下:

使用Android AsyncTask異步線程

最後,放出資源位址,有興趣可以去下載下傳個回去看看。

Android異步線程使用Demo