我想我已经看到了一些实现。基本思路大致是
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 和 Looper 等 Android 特定的东西的情况下仅使用纯 Java 来实现相同的效果。
Looper、Handler 以及所有这些逻辑背后的消息队列主要由纯 Java 组成。通用解决方案的问题是您无法“注入”代码以运行到线程中。线程必须定期检查某种任务队列,看看是否有东西要运行。
如果你写这样的代码
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() 和类似的做大致相同的事情。只有多个线程在单个队列中等待代码。
作为这个问题的扩展,是否可以做同样的事情,但不仅是使用 UI 线程,而是使用任何特定线程,在哪里调用异步方法?
一般的答案是否定的。只有当有办法注入代码以在该线程中运行时。