【问题标题】:Does starting an AsyncTask inside onResume method does cost more memory?在 onResume 方法中启动 AsyncTask 会消耗更多内存吗?
【发布时间】:2018-01-10 07:56:09
【问题描述】:

我使用AsyncTask 从本地数据库(sqlite)更新列表,如下所示:

 @Override
    public void onResume() {
        super.onResume();
       new MyAsynctask().execute();

    }

我需要清楚地解释每次执行新的 MyAsynctask 时会发生什么,之​​前创建的前一个 MyAsynctask 会发生什么,以及这种方式是否会占用更多内存?

【问题讨论】:

  • 问题是:每次在您的活动中调用 onResume 时,都会创建并执行一个新的 MyAsynctask。巨大的内存泄漏:o。你必须自己停止它并重新创建它!
  • 请告诉我停止 MyAsynctask 并重新创建它的最佳做法
  • @ReneFerrari 你怎么判断这是一个(巨大的)内存泄漏?一旦异步任务结束,它就会被清理
  • 我认为他的意思是 OutOfMemory 而不是内存泄漏。
  • 对我来说内存泄漏定义为您没想到的东西仍在运行并消耗内存。您的问题是,如果 onResume() 被多次调用,则许多 AsyncTask 并行运行。因此,内存消耗会增加很多,并且正如 Enzokie 提到的那样会导致 OutOfMemory。 ADM 已经写了一个答案,解释了如何避免这种情况:)

标签: java android multithreading android-asynctask


【解决方案1】:

您的新异步任务什么都不做。

AsyncTask 一个接一个地执行。

只有当你的旧异步任务结束时,新的异步任务才会开始运行。

【讨论】:

  • 异步任务何时终止??
  • 一个 ayct 任务在 doInBackground() 结束时和 onPostExecute() 之后结束。
【解决方案2】:

AsyncTask 只是一个线程的实现,用于管理后台任务和 UI 更新。 AsyncTask 被设计为在 android 中围绕 ThreadHandler 的辅助类。来自文档。

AsyncTask 允许正确且轻松地使用 UI 线程。此类允许您执行后台操作并在 UI 线程上发布结果,而无需操作线程和/或处理程序。

因此,对于您每次致电new MyAsynctask().execute(); 时的问题,都会启动一个新线程。如果没有完成,旧的也会运行。

要取消上一个任务,您可以使用任务的全局实例并检查状态是否为 RUNNING by getStatus()

 if(asyncTask!=null && asyncTask.getStatus()== AsyncTask.Status.RUNNING){
            asyncTask.cancel(true);
        }

在您的情况下,您在 onResume() 创建新任务,因此每次您的活动恢复时都会创建新线程,这不是刷新屏幕的内存高效解决方案。
有关取消任务的更多详细信息,请阅读部分 Cancelling a taskcancel(boolean)

【讨论】:

  • 不幸的是,如果Activity 被重新创建,AsyncTask 实例也将被重新创建。如果您随后检查状态,它将与新的 asyncTask 实例相关,而不是旧的(可能仍在运行)。我认为他最好手动停止onPause() 中的task
  • 我没有说那个。我只是暗示如何检查状态。 Activity 的生命周期取决于实现和参与。
【解决方案3】:

如果你知道如何管理它,那么它就不是内存泄漏。

您的AsyncTask 将在onResume() 函数内执行,因此它将在以下情况下运行:

  1. 每次Activity 被(重新)创建
  2. 你从另一个Activity回来
  3. 你改变屏幕方向
  4. 你从另一个 Application 回来,由 Intent 开始
  5. 您关闭并重新打开您的App
  6. ...

您可能希望为您的AsyncTask 保留一个类字段并在onCreate() 中实例化它:

private MyAsyncTask asyncTask;

如果Activty没有被破坏(点:1、2(可能)、4(可能)、5(可能)),您可以轻松检查asyncTask状态并在需要时取消它。

问题在于,如果重新创建了 Activity,则当您启动新的 AsyncTask 时,旧的 AsyncTask 可能仍在运行。由于Activity 实例是新实例,asyncTask 引用也将指向一个新对象:在这种情况下,您将在后台运行一个野蛮的Thread

除非Android 的操作系统杀死了Activity 拥有的Thread (不确定),否则您仍然可以通过了解并确保 你的AsyncTask 最多会运行几秒钟,而不会执行任何阻塞 IO 操作。但这并不是真正的工程解决方案。


我想说,最好且更符合标准的解决方案是:通过在 Activity 中保留对 AsyncTask 的引用,只需在 onPause() 中调用 asyncTask.cancel()方法。而且您可以确定AsyncTask 的线程将在您的Activity 暂停或销毁之前被取消。

您的代码将如下所示:

private MyAsyncTask asyncTask;

protected void onCreate() {
    this.asyncTask = new MyAsyncTask();
}

protected void onResume() {
    this.asyncTask.execute();
}

protected void onPause() {
    this.asyncTask.cancel();
}

【讨论】:

    猜你喜欢
    • 2010-10-08
    • 2013-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多