猿问

AsyncTask在概念上是否真的有缺陷,还是我只是遗漏了什么?

AsyncTask在概念上是否真的有缺陷,还是我只是遗漏了什么?

我已经调查了这个问题几个月了,想出了不同的解决方案,我对此并不满意,因为它们都是大规模的黑客。我仍然不能相信,一个在设计上有缺陷的类把它纳入了框架,没有人在谈论它,所以我想我一定是遗漏了什么。

问题在于AsyncTask..根据文件

“允许在UI线程上执行后台操作和发布结果,而不必操作线程和/或处理程序。”

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

原因很明显:如果活动被破坏,从而触发了任务,该怎么办?这可以随时发生,例如,因为你翻转了屏幕。如果任务将保存对创建它的上下文的引用,则不仅保留无用的上下文对象(窗口将被销毁,而且任何UI交互将失败,除非有例外!),您甚至有可能造成内存泄漏。

除非我的逻辑在这里有缺陷,否则这意味着:onPostExecute()这是完全无用的,因为如果您没有访问任何上下文的权限,在UI线程上运行这个方法又有什么好处呢?你不能在这里做任何有意义的事。

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

更重要的是,即使有了这种解决办法,您仍然存在这样的问题:当上下文被破坏时,您仍然会遇到这样的问题。无记录它发射的任务。这意味着在重新创建上下文时,您必须重新启动任何任务,例如,在屏幕方向改变之后。这既慢又浪费。

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

不过,这是一个复杂的解决方案,需要对Droid-Fu库类进行子类处理,这使其成为一种相当有侵扰性的方法。

现在我只想知道:我只是大量地遗漏了一些东西,还是AsyncTask真的完全有缺陷?你的工作经验如何?你是怎么解决这些问题的?

谢谢你的意见。


狐的传说
浏览 360回答 3
3回答

烙印99

像这样的事怎么样:class&nbsp;MyActivity&nbsp;extends&nbsp;Activity&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;Worker&nbsp;mWorker; &nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;class&nbsp;Worker&nbsp;extends&nbsp;AsyncTask<URL,&nbsp;Integer,&nbsp;Long>&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MyActivity&nbsp;mActivity; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Worker(MyActivity&nbsp;activity)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mActivity&nbsp;=&nbsp;activity; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;Long&nbsp;doInBackground(URL...&nbsp;urls)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;count&nbsp;=&nbsp;urls.length; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long&nbsp;totalSize&nbsp;=&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;<&nbsp;count;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;totalSize&nbsp;+=&nbsp;Downloader.downloadFile(urls[i]); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;publishProgress((int)&nbsp;((i&nbsp;/&nbsp;(float)&nbsp;count)&nbsp;*&nbsp;100)); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;totalSize; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;void&nbsp;onProgressUpdate(Integer...&nbsp;progress)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(mActivity&nbsp;!=&nbsp;null)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mActivity.setProgressPercent(progress[0]); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;void&nbsp;onPostExecute(Long&nbsp;result)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(mActivity&nbsp;!=&nbsp;null)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mActivity.showDialog("Downloaded&nbsp;"&nbsp;+&nbsp;result&nbsp;+&nbsp;"&nbsp;bytes"); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;@Override &nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;void&nbsp;onCreate(Bundle&nbsp;savedInstanceState)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super.onCreate(savedInstanceState); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mWorker&nbsp;=&nbsp;(Worker)getLastNonConfigurationInstance(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(mWorker&nbsp;!=&nbsp;null)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mWorker.mActivity&nbsp;=&nbsp;this; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;... &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;@Override &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;Object&nbsp;onRetainNonConfigurationInstance()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;mWorker; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;@Override &nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;void&nbsp;onDestroy()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super.onDestroy(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(mWorker&nbsp;!=&nbsp;null)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mWorker.mActivity&nbsp;=&nbsp;null; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;startWork()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mWorker&nbsp;=&nbsp;new&nbsp;Worker(this); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mWorker.execute(...); &nbsp;&nbsp;&nbsp;&nbsp;}}

ibeautiful

原因很明显:如果活动被破坏,从而触发了任务,该怎么办?手动将活动与AsyncTask在……里面onDestroy()..手动将新活动重新关联到AsyncTask在……里面onCreate()..这需要一个静态内部类或一个标准Java类,外加大约10行代码。
随时随地看视频慕课网APP

相关分类

Android
我要回答