问题 为什么Android的AsyncTask没有实现Future?


在Java中,我已经习惯了 Futures。现在我正在看Android,和 AsyncTask 实现几乎所有相同的方法并涵盖类似的生命周期。但是,如果我想要保持一致并在我的代码中使用Future,我必须将AsyncTask包装在一个愚蠢的包装器中,因为它实际上并没有实现Future。

他们需要添加的只是一个 isDone() 方法,这似乎是微不足道的,然后添加 implements Future<Result>。 (稍后补充:请参阅下面的答案,了解它会有多么微不足道)。

任何Android专家都知道一些很好的理由/模糊的错误,它可能导致为什么没有这样做?


6294
2017-07-14 16:34


起源

该 AsyncTask class的唯一目的是让开发人员轻松实现多线程...我最好猜测为什么他们没有实现它 Future 是因为这是不必要的信息,很容易被抽象出来。 - Alex Lockwood


答案:


我仍然对“为什么”不使用AsyncTask进行未来的理论原因感兴趣。

但是,为了记录,我最终创建了自己的小班(如下所示)。如果你想要一个Future,只需扩展它而不是AsyncTask。 IMO,比@Eng.Fouad在代码中访问私有mFuture的想法更清晰。 (但是感谢这个想法,它让我看了一下源代码!)YMMV。

public abstract class FutureAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> implements Future<Result>{

   @Override
   public boolean isDone() {
      return AsyncTask.Status.FINISHED == getStatus();
   }
}

6
2017-07-14 16:53



19分钟后......“我最终创建了自己的班级......”。听起来你迫不及待地为自己找出答案哈哈。 - Alex Lockwood
起初我以为我必须包装/委托Future的所有方法,这很烦人。但是添加单一的1行方法似乎很容易成为一个明智的选择。 :-) - user949300
AsyncTask已经有了FutureTask字段,第二次实现Future是不合理的。它是一个 有一个 关系,而不是 是-A 关系。 - yorkw
@yorkw Point指出。 AsyncTask已经通过将除Future的一种方法委托给内部私有mFuture来实现“is-a”。为了保持一致性,他们应该添加isDone()并将其委托给完整的“is-a”Future。或者,如果你非常强烈地认为它是一种“有一种”的关系,你也不会对Demeter法则(我不是),我们可以为mFuture添加一个getter,getFuture()。 (而且,虽然为时已晚并且会破坏向后兼容性,但请删除其他方法)。附:喜欢你的SO用户页面上的报价! - user949300
@ user949300,为了向后兼容,你可以随时复制 原始来源 并自定义您自己的com.company.AsyncTask并根据您的要求添加您想要的任何内容,并开始使用您自己的com.company.AsyncTask而不是android.os.AsyncTask。 - yorkw


从阅读实际代码 AsyncTask.java 它实际上 使用 一个 Future 任务,然后更多。一个 Future 是一个在旅途中异步执行的任务。一个 AsyncTask 计划在一个(或池)后台线程的队列上。

一个 AsyncTask 实际上比a更“优越” Future 任务。它确实进行了奇特的调度和优化 Future的功能。只需看看API介绍级别。 Future 是从API 1.0开始引入的。该 AsyncTask 对象是在API 3中引入的。

AsyncTask有一个Future任务,而不是Future。

AsyncTask.java

/**
 * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
 */
public AsyncTask() {
    mWorker = new WorkerRunnable<Params, Result>() {
        public Result call() throws Exception {
            mTaskInvoked.set(true);

            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            //noinspection unchecked
            return postResult(doInBackground(mParams));
        }
    };

    mFuture = new FutureTask<Result>(mWorker) {
        @Override
        protected void done() {
            try {
                postResultIfNotInvoked(get());
            } catch (InterruptedException e) {
                android.util.Log.w(LOG_TAG, e);
            } catch (ExecutionException e) {
                throw new RuntimeException("An error occured while executing doInBackground()",
                        e.getCause());
            } catch (CancellationException e) {
                postResultIfNotInvoked(null);
            }
        }
    };
}

6
2018-05-15 06:57



一个 FutureTask 不是一个 Future虽然是 Future 是。的子类 FutureTask。你好像把这两个弄糊涂了。 - Michael Hampton
看来@MichaelHampton 您 可能会混淆两者 developer.android.com/reference/java/util/concurrent/... “这个类提供了Future的基本实现,以及启动方法......”。 Future的实现意味着该实现 IS 未来 - DritanX
其实你还是很困惑;你提供的报价证明了我的观点。 - Michael Hampton
@MichaelHampton实现接口的类变为类型 接口。该类成为它实现的每种类型的已实现接口。子类化和实现之间存在差异。你似乎有那两个困惑。 - DritanX


AsyncTask 太简单了。它适用于可能需要几秒钟的短任务,但您不想锁定UI线程。如果你真的需要一个 Future,你的任务可能太复杂了 AsyncTask 无论如何。

你可以检查一下的状态 AsyncTask 通过电话 getStatus()。这将返回一个可以是其中之一的枚举 Status.PENDINGStatus.RUNNING 要么 Status.FINISHED


1
2017-07-14 16:43



我不同意你的意见与事实。 - DritanX
@DritanX A. FutureTask 不是一个 Future虽然是 Future 是。的子类 FutureTask。 - Michael Hampton
你真的读过代码吗? 知道区别 接口和子类之间? android.googlesource.com/platform/packages/apps/Gallery2/+/... 在这里,让我帮助你,该课程的签名就像这样开始 public class FutureTask<T> implements Runnable, Future<T> { 检查 那 @MichaelHampton,是的 不 的子类 Future 而是它 器物  Future 因此a FutureTask  是-A  Future - DritanX
我从3D图形包中指出了FutureTask,尽管如此,真正的FutureTask就像它: public class FutureTask<V> implements RunnableFuture<V> { 和 RunnableFuture 好像 public interface RunnableFuture<V> extends Runnable, Future<V> {。这里重要的关键词是 器物 不 扩展。 - DritanX