Android AsyncTask内存泄漏

6

我在这里阅读了一些问题,浏览了一些互联网文章,但是关于AsyncTask中的内存泄漏问题并不清楚。请问您能给我一些建议吗?
让我们考虑一些情况:

1)AsyncTask是一个内部类
我编写了MyAsyncTask来从服务器下载小数据(<1 KB),并将其写入MyActivity代码中(而不是作为静态类)。它将存储对MyActivity实例的隐式引用。如果我开始执行MyAsyncTask.execute(),那么直到此AsyncTask完成之前,MyActivity实例将无法进行垃圾回收。因此,如果我在AsyncTask执行期间旋转屏幕,则旧的MyActivity实例将会在内存中 - 这就是内存泄漏。
我的解决方案是:由于要下载的数据很小,所以我将在MyActivity的onDestroy()方法中取消MyAsyncTask。这样,我有如下MyActivity代码:

public class MyActivity extends Activity {

//views and constants
private MyAsyncTask air;
private ProgressDialog progressDialog;

protected void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    setContentView(R.layout.account_info_layout);
    progressDialog = new ProgressDialog(this);
    //findViewById, etc.

}   

@Override
protected void onStart() {
    super.onStart();
    air = new MyAsyncTask();
    air.execute();
}

@Override
protected void onDestroy() {
    if (air.getStatus() == AsyncTask.Status.RUNNING) {
        air.cancel(true);
    }
    air = null;
    super.onDestroy();
}


class MyAsyncTask extends AsyncTask<Void, Void, String> {

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        UserData.refreshTimer();
        if (!progressDialog.isShowing())
            progressDialog.show();
    }


    @Override
    protected String doInBackground(Void... params) {
        //GET request
        return result;      
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        //handle results
        progressDialog.dismiss();
    }
}

}


那么,如果我的活动实例被销毁,我会取消异步任务,并在onStart()中创建新的实例。这会产生内存泄漏吗?或者由于progressDialog实例,它会产生IllegalArgumentException/NullPointerException吗?我认为不会产生任何异常,因为如果我取消了AsyncTask,则不会调用onPostExecute()。

2) 在自己的文件中使用AsyncTask
下一个情况是当我在其他文件中编写MyAsyncTask,并在构造函数中传递Context实例。如果我将Context作为WeakReference存储,这种方法会导致内存泄漏吗?在调用Activity中的onDestroy()方法中取消AsyncTask是正确的想法,以避免在onPostExecute()方法期间出现IllegalArgumentException/NullPointerException吗?或者,避免这些异常的另一种方法是检查我的Context变量是否为null。

其他方法:我听说过Otto库,关于使用保留的Fragment,但现在我想理解这些问题。如果有人知道,请回答。

2个回答

8
  1. 取消操作是解决内存泄漏的好方法。你可能需要考虑在onStop中取消,因为你在onStart中设置了一个新任务。你可能需要将此与在onStop中解除progressDialog相关联,因为你正在取消任务。

  2. 如果你取消任务,就不会导致内存泄漏。如果不取消,则可能会导致临时内存泄漏。例如,你可以通过使用context.getApplicationContext()而不是正常的getContext / this(Activity)来构建新的java文件来解决这个问题(应用程序在方向更改时仍然存在)。但你无法在onPostExecute()中访问对话框。相反,你可以使用回调到监听器。使活动实现监听器(并在onStop中分离它)。但取消也是一个很好的方法。


谢谢你的回答!但我不明白,为什么在onStop()中取消请求会更好? - user3533397
3
主要是因为它与 onStart 相呼应。你的流程可能是 onCreate - onStart - onStop - onStart - onStop - onDestroy = 你已经启动了两个任务但仅取消了一个 = 内存泄漏仍然存在。 - Frank

1
顺便提一下,取消异步任务并不意味着它会立即被取消。我建议您切换到Intent Services、Handlers或者如果可能的话使用RXJava。与异步任务不同的是,您可能需要嵌套异步任务来执行多个操作,而使用RXJava,您可以链接这些操作,应用过滤器和不同的转换,并在工作线程上运行该代码。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接