本文位址: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)
參數:
- Params, 開始任務前傳入參數,注意的是,可變長輸入,可以一次性啟動執行多個下載下傳任務,例如傳入一組String[];
- Progress,在背景任務計算時,向外釋出程序的機關,一般是Int或者Double或者其他;
- Result,背景任務計算結束後,傳回的結果
注意以上三個參數皆可為空,隻需要傳入AsyncTask<Void,Void,Void>即可。
程序4部曲:(其實還有1個~)
- onPreExecute(),在UI線程調用,然後立刻被執行。這個過程一般用來做一些初始化操作,例如顯示出一個ProgressBar提示使用者任務已經在執行中、例如讓啟動任務的Button變為Disabled,防止多次執行;
- doInBackground(Params...),當onPreExecute()執行完畢,會立刻在背景線程調用。這個過程一般用來做一些比較耗時的操作,如計算PI(當然沒人這麼無聊吧~)、例如下載下傳網絡圖檔,結果将會傳給最後一個過程onPostExecute(Result)。當然為了使你的程式更加友好,可以顯示進度,而具體進度如何,就是通過在這個過程調用 publishProgress(Progress...) 來向外(指UI線程)釋出程序。
- onProgressUpdate(Progress...),當 publishProgress(Progress...)被調用時,會在UI線程調用此方法。一般是用來提示使用者進度,例如用在Notification上面顯示下載下傳進度條;
- onPostExecute(Result),當任務結束時在UI線程調用,傳入參數為doInBackground()的結果~~
- onCancelled(),在AsyncTask的cancel()方法被調用時觸發調用。
以下是一個自己寫的Demo,有一個按鈕,按鈕啟動異步任務下載下傳CSDN logo并顯示出來
<注意:以下屬性match_parent須在Android2.2之後才可以支援,效果同Android2.1及之前的fill_parent>
AsyncTaskDemoActivity.java [java] view plain copy print ?
- package com.csheng.asynctask;
- import java.io.InputStream;
- import java.net.URL;
- import java.net.URLConnection;
- import android.app.Activity;
- import android.graphics.Bitmap;
- import android.graphics.BitmapFactory;
- import android.os.AsyncTask;
- import android.os.Bundle;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- import android.widget.ImageView;
- public class AsyncTaskDemoActivity extends Activity {
- public static final String TAG = "AsyncTaskDemoActivity";
- private Button downloadBtn = null;
- private ImageView logoIv = null;
- private final String LOGO_URL = "http://csdnimg.cn/www/images/csdnindex_logo.gif";
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- findViews();
- }
- private void findViews() {
- downloadBtn = (Button) findViewById(R.id.downloadBtn);
- logoIv = (ImageView) findViewById(R.id.logoIv);
- downloadBtn.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- new DownloadAsyncTask().execute(LOGO_URL);// 啟動匿名任務
- }
- });
- }
- private class DownloadAsyncTask extends AsyncTask<String, Void, Bitmap> {
- @Override
- protected Bitmap doInBackground(String... params) {
- final String urlStr = params[0];// 取出execute所傳入參數
- URL url = null;
- try {
- url = new URL(urlStr);
- final URLConnection connection = url.openConnection();
- final InputStream inputStream = connection.getInputStream();
- final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
- if (bitmap != null) {
- return bitmap;// 交給onPostExecute()處理
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
- @Override
- protected void onPostExecute(Bitmap result) {
- if (result != null) {
- logoIv.setImageBitmap(result);// 取出doInBackground()的計算結果
- }
- downloadBtn.setEnabled(true);
- super.onPostExecute(result);
- }
- @Override
- protected void onPreExecute() {
- downloadBtn.setEnabled(false);// 在整個異步下載下傳期間,不允許重新啟動下載下傳任務
- super.onPreExecute();
- }
- }
- }
main.xml
[html] view plain copy print ?
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
- <Button
- android:id="@+id/downloadBtn"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerHorizontal="true"
- android:text="@string/downloadText" />
- <!-- 圖檔放置于按鈕下方 -->
- <ImageView
- android:id="@+id/logoIv"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@+id/downloadBtn"
- android:layout_centerHorizontal="true"
- android:contentDescription="@string/contentDescription" />
- </RelativeLayout>
strings.xml [html] view plain copy print ?
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <string name="app_name">AsyncTaskDemo</string>
- <string name="downloadText">下載下傳圖檔</string>
- <string name="contentDescription">這是一張圖檔</string>
- <string name="startDownloadToast">開始下載下傳圖檔</string>
- <string name="setImageToast">設定圖檔資源</string>
- </resources>
對了,還有一個Manifest檔案,别忘了添加網絡權限
AndroidManifest.xml
[html] view plain copy print ?
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.csheng.asynctask"
- android:versionCode="1"
- android:versionName="1.0" >
- <uses-sdk android:minSdkVersion="8" />
- <uses-permission android:name="android.permission.INTERNET" />
- <application
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name" >
- <activity
- android:name=".AsyncTaskDemoActivity"
- android:label="@string/app_name" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
- </manifest>
再來個圖檔刺激下~~效果如下:
最後,放出資源位址,有興趣可以去下載下傳個回去看看。
Android異步線程使用Demo