Android中AsyncTask詳細介紹_Android

來源:互聯網
上載者:User

AsyncTask是一個很常用的API,尤其非同步處理資料並將資料應用到視圖的操作場合。其實AsyncTask並不是那麼好,甚至有些糟糕。本文我會講AsyncTask會引起哪些問題,如何修複這些問題,並且關於AsyncTask的一些替代方案。

AsyncTask

從Android API 3(1.5 Cupcake)開始,AsyncTask被引入用來協助開發人員更簡單地管理線程。實際上在Android 1.0和1.1也是有類似的實現,那就是UserTask。UserTask和AsyncTask有著相同的API及實現,但是由於由於1.0和1.1的裝置份額微乎其微,這裡的概念就不會涉及到UserTask。

生命週期

關於AsyncTask存在一個這樣廣泛的誤解,很多人認為一個在Activity中的AsyncTask會隨著Activity的銷毀而銷毀。然後事實並非如此。AsyncTask會一直執行doInBackground()方法直到方法執行結束。一旦上述方法結束,會依據情況進行不同的操作。

1.如果cancel(boolean)調用了,則執行onCancelled(Result)方法
2.如果cancel(boolean)沒有調用,則執行onPostExecute(Result)方法

AsyncTask的cancel方法需要一個布爾值的參數,參數名為mayInterruptIfRunning,意思是如果正在執行是否可以打斷,如果這個值設定為true,表示這個任務可以被打斷,否則,正在執行的程式會繼續執行直到完成。如果在doInBackground()方法中有一個迴圈操作,我們應該在迴圈中使用isCancelled()來判斷,如果返回為true,我們應該避免執行後續無用的迴圈操作。

總之,我們使用AsyncTask需要確保AsyncTask正確地取消。

不好好工作的cancel()

簡而言之的答案,有時候起作用。

如果你調用了AsyncTask的cancel(false),doInBackground()仍然會執行到方法結束,只是不會去調用onPostExecute()方法。但是實際上這是讓應用程式執行了沒有意義的操作。那麼是不是我們調用cancel(true)前面的問題就能解決呢?並非如此。如果mayInterruptIfRunning設定為true,會使任務儘早結束,但是如果的doInBackground()有不可打斷的方法會失效,比如這個BitmapFactory.decodeStream() IO操作。但是你可以提前關閉IO流並捕獲這樣操作拋出的異常。但是這樣會使得cancel()方法沒有任何意義。

記憶體泄露

還有一種常見的情況就是,在Activity中使用非靜態匿名內部AsyncTask類,由於Java內部類的特點,AsyncTask內部類會持有外部類的隱式引用。詳細請參考細話Java:”失效”的private修飾符,由於AsyncTask的生命週期可能比Activity的長,當Activity進行銷毀AsyncTask還在執行時,由於AsyncTask持有Activity的引用,導致Activity對象無法回收,進而產生記憶體泄露。

結果丟失

另一個問題就是在旋轉螢幕等造成Activity重新建立時AsyncTask資料丟失的問題。當Activity銷毀並創新建立後,還在啟動並執行AsyncTask會持有一個Activity的非法引用即之前的Activity執行個體。導致onPostExecute()沒有任何作用。

串列還是並行

關於AsyncTask時串列還是並行有很多疑問,這很正常,因為它經過多次的修改。如果你並不明白什麼時串列還是並行,可以通過接下來的例子瞭解,假設我們在一個方法體裡面有如下兩行代碼

複製代碼 代碼如下:

new AsyncTask1().execute();
new AsyncTask2().execute();

上面的兩個任務時同時執行呢,還是AsyncTask1執行結束之後,AsyncTask2才能執行呢?實際上是結果依據API不同而不同。

在1.6(Donut)之前:

在第一版的AsyncTask,任務是串列調度。一個任務執行完成另一個才能執行。由於串列執行任務,使用多個AsyncTask可能會帶來有些問題。所以這並不是一個很好的處理非同步(尤其是需要將結果作用於UI試圖)操作的方法。

從1.6到2.3(Gingerbread)

後來Android團隊決定讓AsyncTask並行來解決1.6之前引起的問題,這個問題是解決了,新的問題又出現了。很多開發人員實際上依賴於順序執行的行為。於是很多並發的問題蜂擁而至。

3.0(Honeycomb)到現在

好吧,開發人員可能並不喜歡讓AsyncTask並行,於是Android團隊又把AsyncTask改成了串列。當然這一次的修改並沒有完全禁止AsyncTask並行。你可以通過設定executeOnExecutor(Executor)來實現多個AsyncTask並行。關於API文檔的描述如下

複製代碼 代碼如下:

If we want to make sure we have control over the execution, whether it will run serially or parallel, we can check at runtime with this code to make sure it runs parallel:

複製代碼 代碼如下:

public static void execute(AsyncTask as) {
  if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB_MR1) {
      as.execute();
  } else {
      as.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
  }
}
//(This code does not work for API lvl 1 to 3)

真的需要AsyncTask麼

並非如此,使用AsyncTask雖然可以以簡短的代碼實現非同步作業,但是正如本文提到的,你需要讓AsyncTask正常工作的話,需要注意很多條條框框。推薦的一種進行非同步作業的技術就是使用Loaders。這個方法從Android 3.0 (Honeycomb)開始引入,在android支援包中也有包含。可以通過查看官方的文檔來詳細瞭解Loaders。

本次譯文對原文有少部分刪減修改處理。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.