是AsyncTask真的在概念上有缺陷还是我只是错过了什么? [英] Is AsyncTask really conceptually flawed or am I just missing something?

查看:205
本文介绍了是AsyncTask真的在概念上有缺陷还是我只是错过了什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经研究了这个问题数月了,想出了不同的解决方案,我不满意,因为他们都是大规模的黑客。我仍然不能相信一个有缺陷的设计的类使它成为框架,没有人在谈论它,所以我想我只是必须缺少的东西。

I have investigated this problem for months now, came up with different solutions to it, which I am not happy with since they are all massive hacks. I still cannot believe that a class that flawed in design made it into the framework and no-one is talking about it, so I guess I just must be missing something.

问题是 AsyncTask 。根据文档,


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

"allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers."

示例继续显示一些示例 showDialog()方法在 onPostExecute()中调用。然而,这看起来完全困惑,因为显示一个对话框总是需要一个有效的上下文的引用,并且一个AsyncTask 必须从不持有对上下文对象的强引用。

The example then continues to show how some exemplary showDialog() method is called in onPostExecute(). This, however, seems entirely contrived to me, because showing a dialog always needs a reference to a valid Context, and an AsyncTask must never hold a strong reference to a context object.

原因很明显:如果活动被销毁而触发了任务,该怎么办?这可以发生在所有的时间,例如。因为你翻转了屏幕。如果任务持有对创建它的上下文的引用,那么你不仅持有一个无用的上下文对象(该窗口将被破坏,并且任何 UI交互都将失败,并出现异常! )

The reason is obvious: what if the activity gets destroyed which triggered the task? This can happen all the time, e.g. because you flipped the screen. If the task would hold a reference to the context that created it, you're not only holding on to a useless context object (the window will have been destroyed and any UI interaction will fail with an exception!), you even risk creating a memory leak.

除非我的逻辑在这里有缺陷,否则转换为: onPostExecute()是完全无用的,因为如果你没有访问任何上下文,这个方法在UI线程上运行有什么好处?

Unless my logic is flawed here, this translates to: onPostExecute() is entirely useless, because what good is it for this method to run on the UI thread if you don't have access to any context? You can't do anything meaningful here.

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

One workaround would be to not pass context instances to an AsyncTask, but a Handler instance. That works: since a Handler loosely binds the context and the task, you can exchange messages between them without risking a leak (right?). But that would mean that the premise of AsyncTask, namely that you don't need to bother with handlers, is wrong. It also seems like abusing Handler, since you are sending and receiving messages on the same thread (you create it on the UI thread and send through it in onPostExecute() which is also executed on the UI thread).

最重要的是,即使有解决方法,你仍然有一个问题,当上下文被销毁,你有任务的记录。这意味着您必须在重新创建上下文时重新启动任何任务,例如在屏幕方向改变之后。这是缓慢而浪费的。

To top it all off, even with that workaround, you still have the problem that when the context gets destroyed, you have no record of the tasks it fired. That means that you have to re-start any tasks when re-creating the context, e.g. after a screen orientation change. This is slow and wasteful.

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

My solution to this (as implemented in the Droid-Fu library) is to maintain a mapping of WeakReferences from component names to their current instances on the unique application object. Whenever an AsyncTask is started, it records the calling context in that map, and on every callback, it will fetch the current context instance from that mapping. This ensures that you will never reference a stale context instance and you always have access to a valid context in the callbacks so you can do meaningful UI work there. It also doesn't leak, because the references are weak and are cleared when no instance of a given component exists anymore.

仍然,它是一个复杂的解决方法,

Still, it is a complex workaround and requires to sub-class some of the Droid-Fu library classes, making this a pretty intrusive approach.

现在我只想知道:我是一个非常有趣的方法只是大量地丢失的东西或者AsyncTask真的完全有缺陷?您的体验如何使用它?您是如何解决这些问题的?

Now I simply want to know: Am I just massively missing something or is AsyncTask really entirely flawed? How are your experiences working with it? How did you solve these problem?

感谢您的输入。

推荐答案

p>这样的事情:

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(...);
    }
}

这篇关于是AsyncTask真的在概念上有缺陷还是我只是错过了什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆