1. 程式人生 > >Android之AsyncTask的記憶體洩露問題

Android之AsyncTask的記憶體洩露問題

AsyncTask是Android提供的一種用於非同步處理資料的非同步類,使用AsyncTask可以不用直接使用Thread和Handler來處理後臺操作。AsyncTask被引入到Android中就被貼上了"無憂執行緒"的標籤,目的是為了讓子執行緒與UI執行緒互動更加簡單容易。AsyncTask其本質是一個由5個核心執行緒組成的,最大佇列數為128的執行緒池。我們在使用的過程中,通常會重寫doInBackground(Params…) 方法,該方法在子執行緒中,所以比較耗時的操作都可以放在這裡,由於這個方法在子執行緒中所以就不能直接操作UI。我們在doInBackground完成耗時操作之後返回結果,在onPostExecute方法中更新UI,該方法相當於Handler處理UI的方式。雖然說AsyncTask操作簡單,但是AsyncTask並不是毫無缺點的,它的缺點甚至可以說比較糟糕的。

生命週期。有時候我們會認為在Activity中建立的AsyncTask內部類會隨著Activity的銷燬而被銷燬結束。其實並不是這樣,AsyncTask會一直執行,直到doInBackground方法執行完成。此時,如果執行cancel(boolean)操作,onCancelled(Result result) 方法會被執行。這樣AsyncTask佔據的記憶體才會被通知回收。否則,會繼續執行onPostExecute(Result result) 方法。如果我們的Activity銷燬之前,沒有取消 AsyncTask,這有可能讓我們的AsyncTask崩潰(crash)。也就是說我們在Activity銷燬之前要手動cancel掉AsyncTask。因為此時AsyncTask已經沒有存在的意義了。

但是有一點比較坑爹,有時候你即使執行了cancel操作,也未必就會取消AsyncTask的運轉。因為doInBackground方法中有一個不可中斷的操作,比如BitmapFactory.decodeStream(),這個操作會繼續執行下去。所以這個方法裡面不要執行不可以中斷的操作。

記憶體洩露,根據上面對AsyncTask生命週期的分析可以發現,如果AsyncTask被宣告為Activity的非靜態的內部類,那麼AsyncTask會保留一個對建立了AsyncTask的Activity的引用。如果Activity已經被銷燬,AsyncTask的後臺執行緒還在執行,它將繼續在記憶體裡保留這個引用,導致Activity無法被回收,引起記憶體洩露。

所以還是那句話,在Activity銷燬之前cancel掉AsyncTask。即中斷AsyncTask的執行,因為此時已經沒有必要讓AsyncTask繼續執行了。

結果丟失,螢幕旋轉或Activity在後臺被系統殺掉等情況會導致Activity的重新建立,之前執行的AsyncTask會持有一個之前Activity的引用,這個引用已經無效,這時呼叫onPostExecute()再去更新介面將不再生效。

在Android 1.6之前的版本,AsyncTask是序列的,在1.6至2.3的版本,改成了並行的。在2.3之後的版本又做了修改,可以支援並行和序列,當想要序列執行時,直接執行execute()方法,如果需要並行執行,則要執行executeOnExecutor(Executor)。