我已经调查了这个问题几个月了,提出了不同的解决方案,我不满意,因为它们都是巨大的黑客。我仍然无法相信一个在设计上有缺陷的类被纳入框架,而没有人谈论它,所以我想我一定是错过了什么。
问题出在AsyncTask
。根据文档它
"允许执行后台 操作并在 UI线程,而不需要操作 线程和/或处理程序。" < / p >
然后,该示例继续展示如何在onPostExecute()
中调用一些示例性的showDialog()
方法。然而,这对我来说似乎是完全的,因为显示一个对话框总是需要一个有效的Context
引用,以及一个AsyncTask 一定不能持有对上下文对象的强引用吗。
原因很明显:如果触发任务的活动被破坏了怎么办?这种情况经常发生,比如你翻动了屏幕。如果任务保存了对创建它的上下文的引用,那么你不仅保留了一个无用的上下文对象(窗口将被销毁,任何 UI交互将失败并出现异常!),你甚至有可能创建内存泄漏。
除非我的逻辑在这里有缺陷,否则这转化为:onPostExecute()
是完全无用的,因为如果你不能访问任何上下文,这个方法在UI线程上运行有什么好处?你不能在这里做任何有意义的事情。
一个解决方法是不将上下文实例传递给AsyncTask,而是传递给Handler
实例。这是可行的:因为Handler松散地绑定了上下文和任务,所以您可以在它们之间交换消息,而不会有泄漏的风险(对吧?)但这意味着AsyncTask的前提,即您不需要费心处理程序,是错误的。这看起来也像滥用Handler,因为你在同一个线程上发送和接收消息(你在UI线程上创建它,并在onPostExecute()中发送,这也在UI线程上执行)。
最重要的是,即使有了这个变通方法,你仍然有一个问题,当上下文被销毁时,你有它所触发的任务的没有记录。这意味着在重新创建上下文时,你必须重新启动任何任务,例如在屏幕方向改变之后。这既缓慢又浪费。
我对此的解决方案(作为在Droid-Fu库中实现)是在唯一的应用程序对象上维护从组件名称到它们的当前实例的__abc0的映射。每当AsyncTask启动时,它都会在该映射中记录调用上下文,并且在每次回调时,它都会从该映射中获取当前上下文实例。这确保你永远不会引用一个过时的上下文实例而且,你总是可以在回调中访问一个有效的上下文,这样你就可以在那里做有意义的UI工作。它也不会泄漏,因为引用是弱的,当给定组件的实例不再存在时,引用将被清除。
不过,这是一种复杂的解决方法,需要子类化一些Droid-Fu库类,这是一种相当具有侵入性的方法。
现在我只想知道:我只是大量丢失的东西或AsyncTask真的完全有缺陷?你的工作经历如何?你是如何解决这些问题的?
谢谢你的建议。