Android非同步處理二:使用AsyncTask非同步更新UI介面

來源:互聯網
上載者:User

標籤:

在《Android非同步處理一:使用Thread+Handler實現非UI線程更新UI介面》中,我們使用Thread+Handler的方式實現了非同步更新UI介面,這一篇中,我們介紹一種更為簡潔的實現方式:使用AsyncTask非同步更新UI介面。

概述: AsyncTask是在Android SDK 1.5之後推出的一個方便編寫後台線程與UI線程互動的輔助類。AsyncTask的內部實現是一個線程池,每個背景工作會提交到線程池中的線程執行,然後使用Thread+Handler的方式調用回呼函數(如需深入瞭解原理請看《Android非同步處理四:AsyncTask的實現原理》)。

AsyncTask抽象出後台線程啟動並執行五個狀態,分別是:1、準備運行,2、正在後台運行,3、進度更新,4、完成背景工作,5、取消任務,對於這五個階段,AsyncTask提供了五個回呼函數:

1、準備運行:onPreExecute(),該回呼函數在任務被執行之後立即由UI線程調用。這個步驟通常用來建立任務,在使用者介面(UI)上顯示進度條。

2、正在後台運行:doInBackground(Params...),該回呼函數由後台線程在onPreExecute()方法執行結束後立即調用。通常在這裡執行耗時的後台計算。計算的結果必須由該函數返回,並被傳遞到onPostExecute()中。在該函數內也可以使用publishProgress(Progress...)來發布一個或多個進度單位(unitsof progress)。這些值將會在onProgressUpdate(Progress...)中被發布到UI線程。

3. 進度更新:onProgressUpdate(Progress...),該函數由UI線程在publishProgress(Progress...)方法調用完後被調用。一般用於動態地顯示一個進度條。

4. 完成背景工作:onPostExecute(Result),當後台計算結束後調用。後台計算的結果會被作為參數傳遞給這一函數。

5、取消任務:onCancelled (),在調用AsyncTask的cancel()方法時調用

 

AsyncTask的建構函式有三個模板參數:

1.Params,傳遞給背景工作的參數類型。

2.Progress,後台計算執行過程中,進步單位(progress units)的類型。(就是背景程式已經執行了百分之幾了。)

3.Result, 後台執行返回的結果的類型。

AsyncTask並不總是需要使用上面的全部3種類型。標識不使用的類型很簡單,只需要使用Void類型即可。

 

 

例子:與《Android非同步處理一:使用Thread+Handler實現非UI線程更新UI介面》實現的例子相同,我們在後台下載CSDN的LOGO,下載完成後在UI介面上顯示出來,並會類比下載進度更新。

例子工程檔案下載

 AsyncTaskActivity.java

package com.zhuozhuo;import org.apache.http.HttpResponse;import org.apache.http.client.HttpClient;import org.apache.http.client.methods.HttpGet;import org.apache.http.impl.client.DefaultHttpClient;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;import android.widget.ProgressBar;import android.widget.Toast;public class AsyncTaskActivity extends Activity {        private ImageView mImageView;    private Button mButton;    private ProgressBar mProgressBar;        @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);                mImageView= (ImageView) findViewById(R.id.imageView);        mButton = (Button) findViewById(R.id.button);        mProgressBar = (ProgressBar) findViewById(R.id.progressBar);        mButton.setOnClickListener(new OnClickListener() {                        @Override            public void onClick(View v) {                GetCSDNLogoTask task = new GetCSDNLogoTask();                task.execute("http://csdnimg.cn/www/images/csdnindex_logo.gif");            }        });    }        class GetCSDNLogoTask extends AsyncTask<String,Integer,Bitmap> {//繼承AsyncTask        @Override        protected Bitmap doInBackground(String... params) {//處理後台執行的任務,在後台線程執行            publishProgress(0);//將會調用onProgressUpdate(Integer... progress)方法            HttpClient hc = new DefaultHttpClient();            publishProgress(30);            HttpGet hg = new HttpGet(params[0]);//擷取csdn的logo            final Bitmap bm;            try {                HttpResponse hr = hc.execute(hg);                bm = BitmapFactory.decodeStream(hr.getEntity().getContent());            } catch (Exception e) {                                return null;            }            publishProgress(100);            //mImageView.setImageBitmap(result); 不能在後台線程操作ui            return bm;        }                protected void onProgressUpdate(Integer... progress) {//在調用publishProgress之後被調用,在ui線程執行            mProgressBar.setProgress(progress[0]);//更新進度條的進度         }         protected void onPostExecute(Bitmap result) {//背景工作執行完之後被調用,在ui線程執行             if(result != null) {                 Toast.makeText(AsyncTaskActivity.this, "成功擷取圖片", Toast.LENGTH_LONG).show();                 mImageView.setImageBitmap(result);             }else {                 Toast.makeText(AsyncTaskActivity.this, "擷取圖片失敗", Toast.LENGTH_LONG).show();             }         }                  protected void onPreExecute () {//在 doInBackground(Params...)之前被調用,在ui線程執行             mImageView.setImageBitmap(null);             mProgressBar.setProgress(0);//進度條複位         }                  protected void onCancelled () {//在ui線程執行             mProgressBar.setProgress(0);//進度條複位         }            }    }

main.xml

<?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">    <ProgressBar android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/progressBar" style="?android:attr/progressBarStyleHorizontal"></ProgressBar>    <Button android:id="@+id/button" android:text="下載圖片" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>    <ImageView android:id="@+id/imageView" android:layout_height="wrap_content"        android:layout_width="wrap_content" /></LinearLayout>

manifest.xml

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"      package="com.zhuozhuo"      android:versionCode="1"      android:versionName="1.0">    <uses-sdk android:minSdkVersion="10" /><uses-permission android:name="android.permission.INTERNET"></uses-permission>    <application android:icon="@drawable/icon" android:label="@string/app_name">        <activity android:name=".AsyncTaskActivity"                  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>

運行結果:

 

流程說明:

1、  當點擊按鈕時,建立一個task,並且傳入CSDN的LOGO地址(String型別參數,因此AsyncTask的第一個模板參數為String類型)

2、  UI線程執行onPreExecute(),把ImageView的圖片清空,progrssbar的進度清零。

3、  後台線程執行doInBackground(),不可以在doInBackground()操作ui,調用publishProgress(0)更新進度,此時會調用onProgressUpdate(Integer...progress)更新進度條(進度用整形表示,因此AsyncTask的第二個模板參數是Integer)。函數最後返回result(例子中是返回Bitmap類型,因此AsyncTask的第個模板參數是Bitmap)。

4、  當背景工作執行完成後,調用onPostExecute(Result),傳入的參數是doInBackground()中返回的對象。

 

總結:

AsyncTask為我們抽象出一個背景工作的五種狀態,對應了五個回調介面,我們只需要根據不同的需求實現這五個介面(doInBackground是必須要實現的),就能完成一些簡單的背景工作。使用AsyncTask的方式使編寫後台進程和UI進程互動的代碼變得更為簡潔,使用起來更加方便,但是,AsyncTask也有一些缺憾,我們留到以後再講。

 

 

本博文地址:http://blog.csdn.net/mylzc/article/details/6772129,轉載請註明出處

Android非同步處理二:使用AsyncTask非同步更新UI介面

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.