我正在使用来自Guava的ListenableFuture,关于它们的一件好事是,将Executor传递给Futures.addCallback
方法,即,要求在给定的线程/执行程序上执行回调。
在我的Android应用程序中,我希望能够基于UI线程中的ListenableFuture
启动异步执行,并安排一个回调,该回调也将在UI线程上执行。因此,我想以某种方式将UI线程执行器提交到上述的Futures.addCallback
方法。如何实现呢?
或者,换句话说,我想要UI线程的执行程序。它已经在Android中提供了吗,或者,如果我必须创建自己的,我该怎么做?
编辑:作为此问题的扩展,是否可以做同样的事情,但不仅可以使用UI线程,还可以使用任何特定线程来执行对异步方法的调用?
我很高兴知道如何在不使用Android特有的东西Handler
和Looper
的情况下,仅使用纯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()
的线程-而且通常不是您稍后在其中运行代码的线程。Looper
,Handler
和所有这些逻辑后面的消息队列主要由纯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)代码在该线程中运行时。