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