Android 後臺任務(三)AsyncTask

Android 後臺任務(三)AsyncTask

翻譯自:http://blog.stylingandroid.com/archives/833

轉載請註明:http://blog.csdn.net/liaoqianchuan00/article/details/23949649


前面我們使用了線程來讓耗時操作脫離UI線程執行,也介紹了一些在工作線程中如何再去更新主線程的方法。但是當我們爲了頻繁的在UI線程和工作線程之間切換加了很多Runnables時,我們的代碼變得越來越難看。這篇文章,我們來看看AsyncTask怎麼來提供一個更清晰的更新UI的機制。

 

AsyncTask爲我們提供了開一個後臺線程的框架。我們實現一個AsyncTask的子類,重寫他的不同life-cycle點的一些方法,一些方法運行在UI線程,一些運行在後臺工作線程。

 

你必須重寫的一個方法是doInBackground方法,這個方法運行在後臺工作線程,這個地方你需要添加你需要做得一些耗時操作的代碼。其他3個可選的UI線程的方法:

 

1.      onPreExecute:在doInBackground之前執行,你可以在這裏寫上一些出事後的代碼。

2.      onProgressUpdate:在doInBackground執行的同時執行的一些方法,你的耗時操作在進行的時候,你可以在這裏更新UI來顯示進度。

3.      onPostExecute:在doInBackground之後執行,你可以在這裏寫上耗時操作完成之後更新UI的代碼。

 

有個評判的標準就是,當你只需要重寫doInBackground方法的時候,你其實可以直接使用一個簡單的Thread來實現。

 

AsyncTask是一個泛型類, 在定義一個AsyncTask的時候,你需要定義三個類型對象,分別是傳入Task的對象類型(doInBackground傳入的類型),代表進度的對象類型,工作線程返回的類型(doInBackground返回的類型。比如我們有一個任務是需要從網絡上下載東西,同時基於一個整形數值來更新進度條,最後返回一個String值:

class MyAsyncTask extends AsyncTask<URL, Integer,String>

{

    private final Activityactivity;

     

    private ProgressBar progress;

    private int count = 0;

         

    public MyAsyncTask( Activityactivity )

    {

        this.activity= activity;

    }

     

    @Override

    protected void onPreExecute()

    {

        progress= (ProgressBar)

            activity.findViewById(R.id.progress );

    }

 

    @Override

    protected StringdoInBackground( URL... params )

    {

        Stringret = null;

        count= params.length;

        for(int i = 0; i < count; i++ )

        {

            publishProgress(i );

            //Do something which

            //populates "ret"

        }

        returnret;

    }

         

    @Override

    protected voidonProgressUpdate( Integer... values )

    {

        progress.setMax(count );

        progress.setProgress(values[0] );

    }

         

    @Override  

    protected void onPostExecute(String result )

    {

        Toast.makeText(activity, result,

            Toast.LENGTH_SHORT).show();

    }

         

}

 

這樣做我們就不需要考慮手動的在UI線程和工作線程之間切換來更新UI了,它都爲我們自動的處理了。

 

要使用它,我們需要創建一個MyAsyncTask的實力,並且調用execute的時候傳入一個或者多個URL參數:

 

public class MyActivity extends Activity

{

    @Override

    public void onCreate( BundlesavedInstanceState )

    {

        super.onCreate(savedInstanceState );

        setContentView(R.layout.main );

 

        //Get some urls

 

        newMyAsyncTask( this ).execute( url1, url2, url3 );

    }

 

使用AsyncTask的一個問題就是,除非開發人員很清楚每個方法在哪個線程上執行,會很容易發生問題。比如,我發現一些人在onPreExecute方法中放入了網絡請求的代碼,這看起來沒有什麼問題,因爲網絡請求已經在AsyncTask中實現了啊,但是其實這個網絡請求仍然在UI線程中執行的。

 

上面例子中還有一個問題就是AsyncTask保存了一個Activity的實例,由於AsyncTask線程池的機制,他的工作線程的生命週期是不確定的,應用程序無法控制的,所以這個時候如果AsyncTask作爲Activity的內部類的話很容易出現內存泄露。而我們直接使用線程的方式要好點,只有在run函數不結束時,纔出現這種內存泄露問題。以後將會單獨用一篇文章來分析。

 

Activityfinish掉了,但是AsyncTask還在執行,會有問題嗎?(需要驗證)

 

在Honeycomb上引入了Loaders,這是另外一個機制來處理耗時操作,他更清晰的區分了那些是在UI線程上執行的,那些是在工作線程上執行的。同時他不需要在任務結束後保持對Context的引用。下一章我們將介紹Loaders。

發佈了31 篇原創文章 · 獲贊 20 · 訪問量 22萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章