Capturando al ejecutor para el subproceso actual

Estoy utilizando ListenableFuture de Guava, y una cosa agradable de ellos es que pasar un Executor al método Futures.addCallback , es decir, pedir a ejecutar la devolución de llamada en un thread / ejecutor determinado.

En mi aplicación de Android, quiero poder iniciar la ejecución asíncrona basada en ListenableFuture en el subproceso de UI y programar una devolución de llamada que también se ejecuta también en el subproceso de UI. Por lo tanto, me gustaría enviar de alguna manera el ejecutor de subprocesos de interfaz de usuario al método Futures.addCallback mencionado anteriormente. ¿Cómo lograrlo?

O, en otras palabras, quiero tener un ejecutor para el hilo de la interfaz de usuario. ¿Está disponible ya en Android, o, si tengo que crear mi cuenta, ¿cómo hago eso?

EDIT: Como una extensión de esta pregunta, ¿es posible hacer lo mismo, pero no sólo con el hilo de interfaz de usuario, pero con cualquier hilo en particular, donde se realiza la llamada al método asíncrono?

Me encantaría saber cómo lograr el mismo efecto sin recurrir a las cosas específicas de Android como Handler y Looper , sólo con Java puro.

3 Solutions collect form web for “Capturando al ejecutor para el subproceso actual”

Creo que he visto alguna implementación haciendo eso. La idea básica es más o menos

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

Puede delegar para ejecutar cualquier cosa en el subproceso principal pasándolo a un controlador para el subproceso principal.

Editar: https://github.com/square/retrofit/blob/master/retrofit/src/main/java/retrofit/android/MainThreadExecutor.java por ejemplo

Edit2: Puede configurar el controlador como por ejemplo SensorManager#registerListener(..., Handler handler) permite hacer.

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

La ventaja sobre el uso del looper actual del hilo es que hace explícito qué Looper usted utiliza. En su solución usted toma el Looper de cualquier hilo llama a new ExecuteOnCaller() – y ése no es a menudo el hilo que usted funciona el código adentro más adelante.

Me encantaría saber cómo lograr el mismo efecto sin recurrir a las cosas específicas de Android como Handler y Looper, sólo con Java puro.

Looper , Handler y la cola de mensajes detrás de toda esa lógica están hechos principalmente de Java puro. El problema con una solución genérica es que no se puede "inyectar" código para ejecutar en un subproceso. El hilo debe revisar periódicamente algún tipo de cola de tareas para ver si hay algo que ejecutar.

Si escribe código como

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

Entonces no hay manera de hacer ese hilo hacer cualquier otra cosa pero constantemente imprimir "Hola". Si pudieras hacerlo sería como insertar dinámicamente un salto a otro código en el código del programa. Eso sería IMO una idea terrible.

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

Por otra parte es un hilo simple que los bucles para siempre en una cola. El hilo podría hacer otras tareas intermedias pero hay que agregar una comprobación manual en el código.

Y puede enviarle tareas a través de

  queue.put(new Runnable() { @Override public void run() { System.out.println("Hello!"); } }); 

No hay un controlador especial definido aquí, pero ese es el núcleo de lo que Handler & Looper hacer en Android. Handler en Android le permite definir una devolución de llamada para un Message lugar de sólo un Runnable .

Executors.newCachedThreadPool() y similares hacen más o menos lo mismo. Hay sólo varios subprocesos esperando en código en una sola cola.


Como una extensión de esta pregunta, ¿es posible hacer lo mismo, pero no sólo con el hilo de interfaz de usuario, pero con cualquier hilo en particular, donde se realiza el método de llamada a asíncrona?

La respuesta genérica es No. Sólo si hay una forma de inyectar código para ejecutar en ese hilo.

Basado en asnwer de @zapl, aquí está mi implementación, que también responde a la pregunta editada (extendida): https://gist.github.com/RomanIakovlev/8540439

Calculado también lo pondré aquí, en caso de que el enlace se pudra un día:

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

Mi patrón para usarlo sería así:

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

Utilice com.google.android.gms.tasks.TaskExecutors.MAIN_THREAD .

Un Ejecutor que utiliza el hilo principal de la aplicación.

Fuente: Android docs

Las API de tareas forman parte de los servicios de Google Play desde la versión 9.0.0 .

  • Android en la aplicación de facturación de la clave pública en el repositorio público
  • Java.lang.IllegalStateException: Cifrado no inicializado
  • Cómo mostrar / ocultar elemento de barra de acciones mediante programación mediante Evento de clics
  • División de una cadena en Java lanza PatternSyntaxException
  • Android Speech Recognition API no funciona en Android 7 Nougat
  • Costo de invocar un método en Android
  • Cómo ofuscar con ProGuard pero mantener los nombres legibles durante la prueba?
  • Obtener id generado después de insertar
  • Análisis de archivos XML grandes utilizando el analizador SAX (salte algunas líneas / etiquetas)
  • Abrir una imagen en la galería utilizando la ruta del archivo
  • escuchar todos los eventos clave en un teclado suave Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.