是AsyncTask的真正概念上有缺陷或我只是失去了一些东西? [英] Is AsyncTask really conceptually flawed or am I just missing something?

查看:151
本文介绍了是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 。根据该文件是

The problem is with AsyncTask. According to the documentation it

允许执行背景   操作和公布结果   无需操作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.

原因是显而易见的:如果该活动被破坏而引发的任务是什么?发生这种情况的时候,例如因为你翻转屏幕。如果任务将举行一个引用创建它的背景下,你不仅坚持着一个无用的上下文对象(窗口将被摧毁,任何的用户界面交互将异常失败! ),你甚至可能建立一个内存泄漏。

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的,但处理程序实例。这一工程:因为处理程序松散结合上下文和任务,就可以不用冒着泄漏交换它们之间的消息(是吗?)。但是,这将意味着的AsyncTask,的premise即你不必费心处理,是错误的。这也似乎是滥用处理程序,因为你是发送和在同一个线程接收消息(你在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的福库实施)是维持<$的映射C C>的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.

不过,这是一个复杂的解决方法,并要求到子类的一些Droid的福库类,使之成为一个pretty的侵入性的方法。

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?

感谢您的输入。

推荐答案

怎么是这样的:

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天全站免登陆