我正在使用来自Guava的ListenableFuture,关于它们的一件好事是,将Executor传递给Futures.addCallback方法,即,要求在给定的线程/执行程序上执行回调。
在我的Android应用程序中,我希望能够基于UI线程中的ListenableFuture启动异步执行,并安排一个回调,该回调也将在UI线程上执行。因此,我想以某种方式将UI线程执行器提交到上述的Futures.addCallback方法。如何实现呢?
或者,换句话说,我想要UI线程的执行程序。它已经在Android中提供了吗,或者,如果我必须创建自己的,我该怎么做?
编辑:作为此问题的扩展,是否可以做同样的事情,但不仅可以使用UI线程,还可以使用任何特定线程来执行对异步方法的调用?
我很高兴知道如何在不使用Android特有的东西HandlerLooper的情况下,仅使用纯Java来实现相同的效果。

最佳答案

我想我已经看到一些实现方式。基本思路大致是

class UiThreadExecutor implements Executor {
    private final Handler mHandler = new Handler(Looper.getMainLooper());

    @Override
    public void execute(Runnable command) {
        mHandler.post(command);
    }
}

您可以将任何内容传递给主线程的处理程序,以委派运行任何内容。

编辑:https://github.com/square/retrofit/blob/master/retrofit/src/main/java/retrofit/android/MainThreadExecutor.java例如

Edit2:您可以配置处理程序,例如 SensorManager#registerListener(..., Handler handler) 允许您执行此操作。
class HandlerThreadExecutor implements Executor {
    private final Handler mHandler;
    public HandlerThreadExecutor(Handler optionalHandler) {
        mHandler = optionalHandler != null ? optionalHandler : new Handler(Looper.getMainLooper());
    }

    @Override
    public void execute(Runnable command) {
        mHandler.post(command);
    }
}

与使用当前线程的循环程序相比,其优势在于,它可以使您明确使用所使用的Looper。在您的解决方案中,您可以使用Looper调用任何称为new ExecuteOnCaller()的线程-而且通常不是您稍后在其中运行代码的线程。


LooperHandler和所有这些逻辑后面的消息队列主要由纯Java组成。通用解决方案的问题在于,您无法“注入(inject)”代码以运行到线程中。线程必须定期检查某种任务队列,以查看是否有要运行的东西。

如果您编写类似的代码
    new Thread(new Runnable() {
        @Override
        public void run() {
            while (!Thread.interrupted()) {
                System.out.println("Hello");
            }
        }
    }).start();

然后,除了不断打印“Hello”之外,没有其他方法可以使该线程执行任何其他操作。如果可以的话,这就像在程序代码中动态插入到其他代码的跳转一样。 IMO将是一个可怕的想法。
    final BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                while (true) {
                    Runnable codeToRunInThisThread = queue.take();
                    codeToRunInThisThread.run();
                }
            } catch (InterruptedException ignored) {}
        }
    }).start();

另一方面,一个简单的线程会在队列中永远循环。该线程可以在两者之间执行其他任务,但是您必须在代码中添加手动检查。

您可以通过发送任务
    queue.put(new Runnable() {
        @Override
        public void run() {
            System.out.println("Hello!");
        }
    });

这里没有定义特殊的处理程序,但这是Handler&Looper在Android中所做的工作的核心。 Android中的Handler允许您定义Message的回调,而不仅仅是Runnable
Executors.newCachedThreadPool()和类似的代码做大致相同的事情。在一个队列中只有多个线程在等待代码。



通用答案是“否”。仅当有一种方法可以注入(inject)代码在该线程中运行时。

07-24 09:45
查看更多