为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

狐的传说 2019-07-08 14:53:18
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真的完全有缺陷?你的工作经验如何?你是怎么解决这些问题的?谢谢你的意见。
查看完整描述

3 回答

?
烙印99

TA贡献1829条经验 获得超13个赞

像这样的事怎么样:

class MyActivity extends Activity {
    Worker mWorker;

    static class Worker extends AsyncTask<URL, Integer, Long> {
        MyActivity mActivity;

        Worker(MyActivity activity) {
            mActivity = activity;
        }

        @Override
        protected Long doInBackground(URL... urls) {
            int count = urls.length;
            long totalSize = 0;
            for (int i = 0; i < count; i++) {
                totalSize += Downloader.downloadFile(urls[i]);
                publishProgress((int) ((i / (float) count) * 100));
            }
            return totalSize;
        }

        @Override
        protected void onProgressUpdate(Integer... progress) {
            if (mActivity != null) {
                mActivity.setProgressPercent(progress[0]);
            }
        }

        @Override
        protected void onPostExecute(Long result) {
            if (mActivity != null) {
                mActivity.showDialog("Downloaded " + result + " bytes");
            }
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mWorker = (Worker)getLastNonConfigurationInstance();
        if (mWorker != null) {
            mWorker.mActivity = this;
        }

        ...
    }

    @Override
    public Object onRetainNonConfigurationInstance() {
        return mWorker;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mWorker != null) {
            mWorker.mActivity = null;
        }
    }

    void startWork() {
        mWorker = new Worker(this);
        mWorker.execute(...);
    }}


查看完整回答
反对 回复 2019-07-08
?
ibeautiful

TA贡献1993条经验 获得超5个赞

原因很明显:如果活动被破坏,从而触发了任务,该怎么办?

手动将活动与AsyncTask在……里面onDestroy()..手动将新活动重新关联到AsyncTask在……里面onCreate()..这需要一个静态内部类或一个标准Java类,外加大约10行代码。


查看完整回答
反对 回复 2019-07-08
  • 3 回答
  • 0 关注
  • 359 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信