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