搜尋此網誌

2013-10-25

AsyncTask 的黑暗面

作者:囧尼

相信Android App的開發者對於使用AsyncTask肯定不陌生,它提供了一個在背景運算操作又同時能夠更新結果至UI thread的方式。但有幾個小地方可能開發者會容易忽略而導致一些不可預期的結果發生。

Lifecycle


很多人可能認為若在Activity中創建了一個AsyncTask,那當該 Activity被destroyed 時,理論上這個AsyncTask也應該被刪除了才是。答案是錯,這個AsyncTask會繼續在背景執行它的doInBackground(),而這樣的問題會導致Crash的發生,因為它想要refer的一些物件早已經不存在了。

所以我們必須要確認在destroyed Activity的同時,有去取消 (cancel) AsyncTask 掉。呼叫cancel(boolean mayInterruptRunning)來cancel這個task,這個boolean值為true的話,代表當前的task應該立即被中斷,反之則允許處理完當前事務後結束。如果在doInBackground()中有使用道loop的話,建議可以每次呼叫isCancelled()方法來避免掉多餘的處理。

Does cancel really work?


這個答案是有時候,如果你參數的boolean值丟false的話,它會繼續處理至結束為止,但可以避免隨後的onPostExecute()被呼叫到。如果是丟true的話,是不是一定就能中段當前處理而結束呢?也不盡然,因為有些是不能不中斷的操作如BitmapFactory.decodeStream()。


Memory leaks


Activity會保有AsyncTask的reference,但當Activity destroyed的時候,只要此Task還在執行,這reference還是存在,這會導致memory leak的問題發生。


Losing your results


當我們手機進行橫式和直式的改變時,此時Activity會重新創建,但在這之前所執行的AsyncTask卻會因會找不到reference而沒辦法傳回使用者想要的結果。為了解決這個問題,請將AsyncTask的reference放在在global holder中,可以利用Activity.onRetainNonConfigurationInstance 以及 Fragment.setRetainedInstance(true)


Serial or parallel?


到底AsyncTask是照順序來執行還是平行的處理呢?看看下面這段程式碼

究竟Task1和Task2是同時跑,還是Task2會等Task1值行完後再來執行呢?

這取決於API level(因為目前開發顯少用3.0以前的版本,所以之前的就不提)。

Android 3.0以後,Task2是會等待Task1執行完成在去處理的,但如果我又想讓這兩個任務同時執行呢?可以透過 AsyncTask的method executeOnExecutor(Executor)來達成

下面這段程式碼可以用來控制在不同的API版本它都是平行處理這些task的


結論


究竟我們是不是這麼需要AsyncTask呢?其實不然,但如果要使用,要切記這些可能發生的問題。下次在使用這些方便的class同時,也別忘記它們便力的背後可能藏有ㄧ些需要注意的地方。

此外,還有另一個class Loaders ,這個也是能完成在背景處理的需求,有需要的人可以看看。

Reference : 

沒有留言 :

張貼留言