相关疑难解决方法(0)

AsyncTask在概念上是否真的有缺陷,或者我只是缺少某些东西?

我已经调查了这个问题好几个月了,想出了不同的解决方案,我不满意,因为它们都是大规模的黑客攻击.我仍然无法相信一个设计有缺陷的课程已经进入框架而没有人在讨论它,所以我想我一定要错过一些东西.

问题在于AsyncTask.根据它的文件

"允许执行后台操作并在UI线程上发布结果,而无需操纵线程和/或处理程序."

然后该示例继续示出如何showDialog()调用一些示例性方法onPostExecute().然而,这对我来说似乎完全是设计的,因为显示一个对话框总是需要引用一个有效的Context,而AsyncTask 绝不能保持对上下文对象的强引用.

原因很明显:如果活动被破坏而触发任务怎么办?这可能一直发生,例如因为你翻转了屏幕.如果任务将持有对创建它的上下文的引用,那么您不仅要继续使用无用的上下文对象(窗口将被销毁,并且任何 UI交互都会因异常而失败!),您甚至可能会创建一个内存泄漏.

除非我的逻辑在这里有缺陷,否则转换为:onPostExecute()完全没用,因为如果你没有访问任何上下文,这个方法在UI线程上运行有什么用?你不能在这里做任何有意义的事情.

一种解决方法是不将上下文实例传递给AsyncTask,而是传递给Handler实例.这是有效的:因为Handler松散地绑定了上下文和任务,所以你可以在它们之间交换消息而不会有泄漏的风险(对吧?).但这意味着AsyncTask的前提,即您不需要打扰处理程序,是错误的.它似乎也滥用了Handler,因为你在同一个线程上发送和接收消息(你在UI线程上创建它并在onPostExecute()中通过它发送它也在UI线程上执行).

最重要的是,即使使用了这种解决方法,您仍然会遇到这样的问题:当上下文被破坏时,您没有记录它触发的任务.这意味着您必须在重新创建上下文时重新启动任何任务,例如在屏幕方向更改后.这是缓慢而浪费的.

我对此的解决方案(在Droid-Fu库中实现)是维护WeakReferences从组件名称到其唯一应用程序对象上的当前实例的映射.每当启动AsyncTask时,它都会在该映射中记录调用上下文,并且在每次回调时,它将从该映射中获取当前上下文实例.这可以确保您永远不会引用陈旧的上下文实例,并且您始终可以访问回调中的有效上下文,这样您就可以在那里进行有意义的UI工作.它也不会泄漏,因为引用很弱并且在没有给定组件的实例存在时被清除.

尽管如此,这是一个复杂的解决方法,需要对一些Droid-Fu库类进行子类化,这使得这种方法非常具有侵入性.

现在我只想知道:我是否只是大量遗漏某些东西,或者AsyncTask是否真的完全有缺陷?您的使用经验如何?你是怎么解决这些问题的?

感谢您的输入.

concurrency android handler android-asynctask

260
推荐指数
5
解决办法
3万
查看次数

为什么重新启动活动时堆内存会增加?

这个问题与Android中的内存有关.

我的方法:

我有两个活动,A和B.从A,我这样启动B:

Intent i = new Intent(A.this, B.class);
startActivity(i);
Run Code Online (Sandbox Code Playgroud)

在按钮上单击B,我这样做:

B.this.finish();
Run Code Online (Sandbox Code Playgroud)
  • 在B中,我重写onDestroy方法并将所有引用设置为null.
  • 我没有在A的onResume方法中分配新的内存.
  • 我没有泄露上下文.
  • 我没有使用多个线程.
  • 我没有使用服务.
  • B中的所有变量都是私有类变量,并且所有这些变量都在B的onDestroy中设置为null.
  • 此外,B中的ImageViews在onDestroy of B中将其背景设置为null.
  • 我确信B会被摧毁.

结果:

当我在活动A中时,堆内存为7.44 MB.然后,当我启动B并在B上调用完成(从而返回到A)时,堆增加了0.16 MB.再次重复此过程,堆每次增加0.08 MB.

  • 我没有查看堆限制,我正在查看分配的堆.
  • 我在B的onDestroy方法的末尾调用System.gc().

附加信息:

- 我使用MAT来分析内存分配并试图找到这个漏洞.奇怪的是,活动B似乎有5个实例.碰巧的是,我重复了startActivity/finish过程5次.底部条目是活动,其他条目是活动中的监听器:

在此输入图像描述

这是统治者树的截图.我找不到任何异常或怀疑的东西.

支配树

- 我已经观看了关于内存使用(和泄漏)的谷歌IO视频.

题:

无论我做什么,是否有可能始终分配这个0.08 MB的堆(并且不能由GC收集)?如果没有,任何可能导致这种情况的想法?

更新:

  1. 我试图在没有在B中设置内容视图的情况下启动活动B.这意味着B是一个完全空的活动.结果是当我多次重新启动活动时堆内存没有增加.但请注意,这不是解决方案.我必须能够设置内容视图.

  2. scorpiodawg:我尝试在模拟器上运行我的应用程序,堆仍在增长.不错的尝试.

  3. ntc:我把所有出现的"this"更改为"getApplicationContext()"尽可能的地方.我无法调用setContentView(getApplicationContext()); 因为setContentView需要对布局文件的引用,而不是上下文.我做的是创建一个空的布局文件并调用setContentView(emptylayout); 在活动B的onDestroy方法中.这没有帮助.

  4. 我试图删除所有代码,以便只调用setContentView(mylayout).问题持续存在.然后我删除了布局XML文件中的所有gui元素.问题持续存在.唯一剩下的就是容器视图,几个嵌套的线性,相对和滚动布局.我试图删除滚动条中的"android:scrollbarDefaultDelayBeforeFade"属性.结果很好,内存泄漏消失了.然后我放回了我之前删除的所有代码但没有设置"android:scrollbarDefaultDelayBeforeFade"属性并且内存泄漏又回来了.这有多奇怪?

java android memory-leaks memory-management

13
推荐指数
1
解决办法
5292
查看次数