Android AsyncTask導致的記憶體洩漏
一般我們都認為,在一個Activity中的AsyncTask它會隨著當前Activity的銷燬而銷燬,但事實並非如此,AsyncTask會在doInBackground()方法執行完畢之後再結束,所有有些猿人在進入到Activity之後快速的離開該頁面(前提是在非同步中修改頁面佈局),此時App會很無情的給你Crash,一旦doInBackground()方法執行結束,會依據情況進行下一步的操作。但如果呼叫了cancle(boolean)方法,則會執行onCanclled(Result)方法,如果沒有呼叫,則自然而然的呼叫onPostExecute(Result)方法。
說明:cancle(boolean)方法的引數是一個boolean型別的,如果這個值為true,說明當前任務可以打斷,呼叫該方法之後,打斷任務,並執行onCanclled(Result)方法,否則,正在執行的任務會繼續,知道完成任務為止,再呼叫onPostExecute(Result)方法。如果在非同步任務中有迴圈操作,我們就需要在迴圈中通過isCanclled()來進行判斷,當前任務是否已經被取消,如果返回true,我們應該避免後續無用的迴圈操作。但是如果在非同步任務中有雷系BitmapFactory.decodeStream()的IO操作,呼叫cancle方法是無效的,沒有意義的,IO流會丟擲異常資訊,所以不建議使用AsyncTask這個API,可以使用Loader。
言歸正傳,來講下AsyncTask的記憶體洩露的問題,正如上面所說的,他不會隨著Activity的銷燬而銷燬,請看下面的一段示例程式碼:
然而,當我們在此非同步任務還沒有執行完畢的時候去退出當前的這個Activity,此時,這個AsyncTask的生命週期比Activity要長,當Activity銷燬的時候,由於該非同步任務持有該Activity的引用,導致Activity物件無法進行及時的回收,進而產生記憶體洩露的問題,而且,當while尚未執行完畢,該迴圈還有進行,浪費資源。package com.tb.demo.utils.hangview; import android.app.Activity; import android.os.AsyncTask; import android.os.Bundle; /** * Created by tangbin on 15/9/6. */ public class SyncTaskDemoActivity extends Activity { private int today = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 非同步執行任務 new AsyncTask<Object, Void, Boolean>() { @Override protected void onPreExecute() { super.onPreExecute(); } @Override protected Boolean doInBackground(Object... params) { // do something in backfround // 長時間的耗時 while (true) { today++; if (today > 100000) break; } return true; } @Override protected void onPostExecute(Boolean result) { super.onPostExecute(result); if (result) { // success do something } else { // error } } }.execute(); } }
解決思路:在銷燬當前Activity的時候手動去呼叫AsyncTask的cancle方法
修改後的程式碼如下:
package com.tb.demo.utils.hangview; import android.app.Activity; import android.os.AsyncTask; import android.os.Bundle; /** * Created by tangbin on 15/9/6. */ public class SyncTaskDemoActivity extends Activity { private int today = 0; private AsyncTask mAsyncTask; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mAsyncTask = new AsyncTask<Object, Void, Boolean>() { @Override protected void onPreExecute() { super.onPreExecute(); } @Override protected Boolean doInBackground(Object... params) { // do something in backfround // 長時間的耗時 while (true) { if (cancel(true)) break; today++; if (today > 100000) break; } return true; } @Override protected void onPostExecute(Boolean result) { super.onPostExecute(result); if (result) { // success do something } else { // error } } @Override protected void onCancelled() { super.onCancelled(); } }; // 非同步執行任務 mAsyncTask.execute(); } @Override protected void onDestroy() { super.onDestroy(); mAsyncTask.cancel(true); } }