Android中AsyncTask的内存泄露

AsyncTask也是个很常用的API,尤其在异步处理数据并将数据应用到视图的操作场合,介绍如下:

onPreExecute() 

当任务执行之前开始调用此方法,通常在这里显示进度框等;

- doInBackground(Params...)

执行任务的时候调用此方法,在此方法内进行耗时的操作,后台运行,在此方法中可以调用public Progress(Progress...)来更新进度;

- onProgressUpdate(Progress...)

此方法在主线程中执行,用于显示当前执行任务的进度;

- onPostExecute(Result)

此方法在主线程执行,执行完毕的回调,并携带参数;


一般我们都认为,在一个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的销毁而销毁,请看下面的一段示例代码:

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的生命周期比Activity要长,当Activity销毁的时候,由于该异步任务持有该Activity的引用,导致Activity对象无法进行及时的回收,进而产生内存泄露的问题,而且,当while尚未执行完毕,该循环还有进行,浪费资源。

解决思路:在销毁当前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);
    }
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章