捕获当前线程的执行程序

问题描述 投票:11回答:4

我正在使用来自Guava的ListenableFuture,关于它们的一个好处是将Executor传递给Futures.addCallback方法,即要求在给定的线程/执行器上执行回调。

在我的Android应用程序中,我希望能够在UI线程中基于ListenableFuture启动异步执行,并安排一个也在UI线程上执行的回调。因此,我想以某种方式将UI线程执行程序提交到上面提到的Futures.addCallback方法。怎么实现呢?

或者,换句话说,我想拥有UI线程的执行程序。它是否已经在Android中可用,或者,如果我必须创建自己的,我该怎么做?

编辑:作为这个问题的扩展,是否有可能做同样的事情,但不只是与UI线程,但与任何特定的线程,在哪里调用异步方法?

我很乐意知道如何在不使用像Qazxswpoi和Handler这样的特定于Android的东西的情况下实现相同的效果,只需使用纯Java。

java android guava executorservice
4个回答
23
投票

我想我已经看到了一些实现。基本的想法是粗略的

Looper

您可以委派在主线程中运行任何东西,方法是将其传递给主线程的处理程序。

编辑:class UiThreadExecutor implements Executor { private final Handler mHandler = new Handler(Looper.getMainLooper()); @Override public void execute(Runnable command) { mHandler.post(command); } } 例如

Edit2:您可以配置处理程序,例如https://github.com/square/retrofit/blob/master/retrofit/src/main/java/retrofit/android/MainThreadExecutor.java允许你这样做。

SensorManager#registerListener(..., Handler handler)

使用当前线程的looper的优势在于它明确了你使用的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 - 而这通常不是你稍后运行代码的线程。

我很乐意知道如何在不使用像Handler和Looper这样的特定于Android的东西的情况下实现相同的效果,只需使用纯Java。

new ExecuteOnCaller()Looper和所有逻辑背后的消息队列都是由大多数纯Java构成的。通用解决方案的问题在于您无法“注入”代码以运行到线程中。线程必须定期检查某种任务队列,看是否有东西要运行。

如果你写代码

Handler

然后没有办法让该线程做任何其他事情,但不断打印“你好”。如果你能做到这一点就像动态地将跳转到其他代码到程序代码中。这将是一个可怕的想法IMO。

    new Thread(new Runnable() {
        @Override
        public void run() {
            while (!Thread.interrupted()) {
                System.out.println("Hello");
            }
        }
    }).start();

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

你可以通过它发送任务

    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();

这里没有定义特殊处理程序,但这是Handler&Looper在Android中所做的核心。 Android中的 queue.put(new Runnable() { @Override public void run() { System.out.println("Hello!"); } }); 允许您为Handler而不仅仅是Message定义回调。

Runnable和类似的事情大致相同。只有多个线程在单个队列中等待代码。


作为这个问题的扩展,是否有可能做同样的事情,但不仅仅是UI线程,而是任何特定的线程,在那里调用异步方法?

通用答案是否定的。只有在有一种方法可以注入要在该线程中运行的代码时。


7
投票

基于@zapl的回答,这是我的实现,它也回答了编辑(扩展)的问题:qazxsw poi

弄清楚我也会把它放在这里,万一链接会腐烂一天:

Executors.newCachedThreadPool()

我使用它的模式是这样的:

https://gist.github.com/RomanIakovlev/8540439

5
投票

使用package com.example.concurrent; import android.os.Handler; import android.os.Looper; import java.util.concurrent.Executor; /** * When the calling thread has a Looper installed (like the UI thread), an instance of ExecuteOnCaller will submit * Runnables into the caller thread. Otherwise it will submit the Runnables to the UI thread. */ public class ExecuteOnCaller implements Executor { private static ThreadLocal<Handler> threadLocalHandler = new ThreadLocal<Handler>() { @Override protected Handler initialValue() { Looper looper = Looper.myLooper(); if (looper == null) looper = Looper.getMainLooper(); return new Handler(looper); } }; private final Handler handler = threadLocalHandler.get(); @Override public void execute(Runnable command) { handler.post(command); } }

使用主应用程序线程的Executor。

资料来源:/** * in SomeActivity.java or SomeFragment.java */ Futures.addCallback(myModel.asyncOperation(param), new FutureCallback<Void>() { @Override public void onSuccess(Void aVoid) { // handle success } @Override public void onFailure(Throwable throwable) { // handle exception } }, new ExecuteOnCaller());

任务API是Google Play服务com.google.android.gms.tasks.TaskExecutors.MAIN_THREAD的一部分。


0
投票

要解决您的问题和扩展问题,以创建一个只在当前线程上运行并避免Android类的Executor:

Android docs

参见文档:since version 9.0.0

© www.soinside.com 2019 - 2024. All rights reserved.