怎么構(gòu)建AsyncTask

本篇內(nèi)容主要講解“怎么構(gòu)建AsyncTask”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“怎么構(gòu)建AsyncTask”吧!

創(chuàng)新互聯(lián)是一家專注于成都網(wǎng)站設(shè)計、成都做網(wǎng)站與策劃設(shè)計,黔西南州網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)做網(wǎng)站,專注于網(wǎng)站建設(shè)10年,網(wǎng)設(shè)計領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:黔西南州等地區(qū)。黔西南州做網(wǎng)站價格咨詢:13518219792

為什么要使用異步任務(wù)?

  • Android 單線程模型,多線程的操作系統(tǒng)

  • 耗時操作放在非主線程中運(yùn)行

AsyncTask 為何而生?

  • 子線程中更新UI

  • 封裝簡化異步操作

構(gòu)建AsyncTask子類的參數(shù)

AsyncTask

構(gòu)建AsyncTask子類的的回調(diào)方法

doInBackground(): 必須重寫,異步執(zhí)行后臺線程將要完成的任務(wù)

onPreExecute(): 執(zhí)行后臺線程前被調(diào)用,通常用來做一些初始化操作

onPostExecute():當(dāng)doInBackground() 方法完成后系統(tǒng)會自動調(diào) 用,并將doInBackground() 方法的返回值作為參數(shù)春遞給onPostExecute()方法

onProgressUpdate():在doBackground() 方法中調(diào)用publishProgress()方法更新任務(wù)的執(zhí)行進(jìn)度后,就會調(diào)用該方法

接下來我們寫個程序測試一下這些方法的執(zhí)行順序

首先創(chuàng)建一個AsyncTask的子類 MyAsyncTask

public class MyAsyncTask extends AsyncTask<Void, Void, Void>{

    String LOGCAT = "LOGCAT";

    @Override
    protected Void doInBackground(Void... params) {
        Log.d(LOGCAT, "doInBackground------------");
        System.out.println("doInBackground------------");
        return null;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        Log.d(LOGCAT, "onPreExecute");

    }

    @Override
    protected void onPostExecute(Void result) {
        super.onPostExecute(result);
        Log.d(LOGCAT, "onPostExecute");

    }

    @Override
    protected void onProgressUpdate(Void... values) {
        super.onProgressUpdate(values);
        Log.d(LOGCAT, "onProgressUpdate");

    }

}

在 MainActivity 中進(jìn)行測試

public class MainActivity extends Activity

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        MyAsyncTask asyncTask = new

在模擬器上部署運(yùn)行之后,查看Logcat 可以看到下面的日志

怎么構(gòu)建AsyncTask

從日志中可以看到,幾個方法的執(zhí)行順序依次為 : onPreExecute –>doInBackground –>onPostExecute

然后我們在doInBackground 方法中添加這句代碼 publishProgress();

@Override
    protected Void doInBackground(Void... params) {
        Log.d(LOGCAT, "doInBackground------------");

        //調(diào)用該方法后,會執(zhí)行 onPostExecute() 方法
        publishProgress();

        return null;
    }

再次運(yùn)行,觀察logcat 輸出,可看到在 doInBackground() 方法中執(zhí)行了 publishProgress()方法后會調(diào)用 onProgressUpdate() 方法,顧名思義就是更新進(jìn)度條的方法

怎么構(gòu)建AsyncTask

下面我們來看一個典型的異步操作的例子,網(wǎng)絡(luò)操作,從 Android4.0 之后,網(wǎng)絡(luò)操作就嚴(yán)禁被放入到主線程中執(zhí)行.下面是一個采用在異步線程處理下載圖像
在UI線程設(shè)置圖像的例子

布局界面代碼比較簡單,如下

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    <ImageView
        android:id="@+id/iv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"

    <ProgressBar
        android:id="@+id/pb"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:visibility="gone"

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:onClick="loadImage"
        android:text="下載圖片"

</RelativeLayout>

MainActivity代碼如下

public class MainActivity extends Activity

    private ImageView image;// 要展示的圖片
    private ProgressBar pb;// 進(jìn)度條
    // 要加載的圖片的url
    String imageUrl = "/upload/otherpic59/2016_10_09logo_61d59f1e74db0be41ffe1d31fb8edef3.png";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        image = (ImageView) findViewById(R.id.iv);
        pb = (ProgressBar) findViewById(R.id.pb);

    }

    // 下載按鈕的點(diǎn)擊事件
    public void loadImage(View view) {

        AsyncTaskTest asyncTaskTest = new AsyncTaskTest();
        // execute()方法接受一個可變長數(shù)組的參數(shù),可在 doInBackground()方法中獲取
        asyncTaskTest.execute(imageUrl);

    }

    class AsyncTaskTest extends AsyncTask<String, Void, Bitmap> {

        Bitmap bitmap;

        // 下載開始前的一些初始化操作
        @Override
        protected void onPreExecute() {
            // TODO Auto-generated method stub
            super.onPreExecute();
            pb.setVisibility(View.VISIBLE);// 在下載之前將 Progress 顯示出來
        }

        // 在此方法中進(jìn)行網(wǎng)絡(luò)耗時操作,下載完成后會執(zhí)行 onPostExecute 方法,并把返回值傳遞給它
        @Override
        protected Bitmap doInBackground(String... params) {

            // 獲取傳遞進(jìn)來的參數(shù)
            String url = params[0];
            Bitmap btm = null;
            URLConnection connection;
            InputStream is;

            try {
                connection = new URL(url).openConnection();
                is = connection.getInputStream();
                BufferedInputStream bis = new BufferedInputStream(is);
                // 通過 BitmapFactory.decodeStream 方法吧輸入流轉(zhuǎn)換為 bitmap 對象
                bitmap = BitmapFactory.decodeStream(bis);

                is.close();
                bis.close();

            } catch (MalformedURLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            // 為了看清楚進(jìn)度條,人為加一個延時操作,便于觀察
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            return bitmap;
        }

        // doInBackground()方法執(zhí)行完畢后會自動調(diào)用此方法, 此方法的參數(shù)是 doInBackground() 方法的返回值.
        @Override
        protected void onPostExecute(Bitmap result) {
            // TODO Auto-generated method stub
            super.onPostExecute(result);
            pb.setVisibility(View.GONE);// 隱藏進(jìn)度條
            image.setImageBitmap(result);// 顯示下載的網(wǎng)絡(luò)圖片

上面代碼注釋很詳細(xì),不再多做解釋,只要搞懂了 AsyncTask 的幾個方法的作用于執(zhí)行周期,上面的代碼很容易理解.

下面我們再通過一個模擬進(jìn)度條的小例子,進(jìn)一步認(rèn)識AsyncTask 異步任務(wù)的用法

布局界面很簡單,如下

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    <ProgressBar
        android:id="@+id/pb"
        android:padding="10dp"
        
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"

    <TextView
        android:id="@+id/tv_show"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/pb"
        android:layout_centerHorizontal="true"
        android:text="0%"
        android:textAppearance="?android:attr/textAppearanceSmall"

</RelativeLayout>

Activity 代碼也很簡單

public class progressBarTest extends Activity

    private ProgressBar pb;
    private TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.pro);
        pb = (ProgressBar) findViewById(R.id.pb);
        tv = (TextView) findViewById(R.id.tv_show);

        MyAsyncTask myAsyncTask = new MyAsyncTask();
        myAsyncTask.execute();

    }

    class MyAsyncTask extends AsyncTask<Void, Integer, Void> {

        @Override
        protected Void doInBackground(Void... params) {

            //模擬進(jìn)度的更新
            for (int i = 0; i <= 100; i++) {
                // 更新進(jìn)度條,重寫 onProgressUpdate()方法,參數(shù)為 publishProgress(i)的參數(shù)
                publishProgress(i);// 此方法傳入的參數(shù)就是 AsyncTask<Void, Integer,
                                    // Void>的第二個指定的參數(shù)類型

                // 睡眠200毫秒
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }

            return null;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);

            // 更新顯示數(shù)據(jù)
            tv.setText(values[0] + "%");

            // 更新進(jìn)度條
            pb.setProgress(values[0]);// 水平進(jìn)度條的進(jìn)度為百分制

是不是很簡單,但是不要高興太早,對于這個程序,當(dāng)我們點(diǎn)擊下載,然后點(diǎn)擊返回,然后再點(diǎn)擊下載,進(jìn)度條居然等了好久才開始更新

這是為啥呢?

其實(shí)AsyncTask 底層是通過線程池進(jìn)行作用的,當(dāng)一個線程沒有作用完畢的時候,其它線程即必須進(jìn)入線程池進(jìn)行等待,等到前面的線程完事后,才會輪到自己執(zhí)行,所以,當(dāng)我們返回再次進(jìn)入的時候,因?yàn)榍耙粋€線程正在執(zhí)行更新進(jìn)度條操作,所以當(dāng)前線程必須等待前一個AsyncTask執(zhí)行完畢后自己才可以執(zhí)行.

那么如何解決這個問題呢?

其實(shí)很簡單,AsyncTask 框架已經(jīng)為我們考慮到了這個問題,我們可以通過 cancel() 方法來取消掉一個AsyncTask開啟的一個異步任務(wù).此方法接受一個布爾值的參數(shù),

我們要做的很簡單,重寫Activity的 onPause() 方法,把AsyncTask的聲明周期和Activity綁定到一起. 并且在 doInBackground() 方法中做異步判斷.代碼如下

@Override
        protected Void doInBackground(Void... params) {

            // 模擬進(jìn)度的更新
            for (int i = 0; i <= 100; i++) {
                // 當(dāng)收到取消請求時,不要在更新進(jìn)度條,直接break結(jié)束for循環(huán)
                if (isCancelled()) {
                    break;

                }

                // 更新進(jìn)度條,重寫 onProgressUpdate()方法,參數(shù)為 publishProgress(i)的參數(shù)
                publishProgress(i);// 此方法傳入的參數(shù)就是 AsyncTask<Void, Integer,
                                    // Void>的第二個指定的參數(shù)類型

                // 睡眠200毫秒
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }

            return null;
        }

并且在 onProgressUpdate () 方法中也做同樣處理

@Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);

            // 當(dāng)收到取消請求時,不要在更新進(jìn)度條,直接return結(jié)束
            if (isCancelled()) {
                return;
            }

            // 更新顯示數(shù)據(jù)
            tv.setText(values[0] + "%");

            // 更新進(jìn)度條
            pb.setProgress(values[0]);// 水平進(jìn)度條的進(jìn)度為百分制

好了一切都做完了,我們再次運(yùn)行程序可以看到

這里有一個注意事項(xiàng),是關(guān)于AsyncTask 的 cancel(true);方法.其實(shí)當(dāng)我們調(diào)用了 AsyncTask的cancel(true)方法時,并不會中斷當(dāng)前的線程,有人對此做出的解釋是

AsyncTask不會不考慮結(jié)果而直接結(jié)束一個線程。調(diào)用cancel()其實(shí)是給AsyncTask設(shè)置一個”canceled”狀態(tài)。這取決于你去檢查AsyncTask是否已經(jīng)取消,之后決定是否終止你的操作。對于mayInterruptIfRunning——它所作的只是向運(yùn)行中的線程發(fā)出interrupt()調(diào)用。在這種情況下,你的線程是不可中斷的,也就不會終止該線程。

說的不是很清楚,我們可以查看 cancel()方法的源代碼

public boolean cancel(boolean mayInterruptIfRunning) {
        if (!(state == NEW &&
              U.compareAndSwapInt(this, STATE, NEW,
                  mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
            return false;
        try {    // in case call to interrupt throws exception
            if (mayInterruptIfRunning) {
                try {
                    Thread t = runner;
                    if (t != null)
                        t.interrupt();
                } finally { // final state
                    U.putOrderedInt(this, STATE, INTERRUPTED);
                }
            }
        } finally {
            finishCompletion();
        }
        return true;
    }

可以看到,這里只是調(diào)用了該線程的 t.interrupt(); 方法.對java線程中斷機(jī)制的理解在此就顯得非常重要了:

Java的中斷是一種協(xié)作機(jī)制。也就是說調(diào)用線程對象的interrupt方法并不一定就中斷了正在運(yùn)行的線程,它只是要求線程自己在合適的時機(jī)中斷自己,

所以我們要想完全停掉這個線程,最好的做法是通過isCanceled()方法.做出顯影的判斷

到此,相信大家對“怎么構(gòu)建AsyncTask”有了更深的了解,不妨來實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

分享標(biāo)題:怎么構(gòu)建AsyncTask
當(dāng)前URL:http://bm7419.com/article20/jdepjo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制開發(fā)、域名注冊、響應(yīng)式網(wǎng)站、營銷型網(wǎng)站建設(shè)、網(wǎng)站改版、網(wǎng)站營銷

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都做網(wǎng)站