tag studio java android multithreading android-library

java - studio - android tag



¿Cómo implementar la función.get con FutureTask o BackgroundTask usando Android? (3)

Estoy haciendo una biblioteca de Android. Y en mi biblioteca, quiero permitir que un usuario realice una tarea particular ya sea en segundo plano o en el hilo principal .

Quiero hacer algo como esto.

1er Escenario

MyLibabry.with(context) .performSomeTask(<params>) .execute();

Cuando el usuario escribe el código de fragmento anterior. La tarea debe realizarse en segundo plano. Así que devolveré el resultado de la tarea usando cualquier oyente.

Y ahora considera el siguiente código de fragmento.

2do escenario

Result result = MyLibabry.with(context) .performSomeTask(<params>) .get();

Ahora, cuando el usuario adjunte el get () al final de la declaración. La tarea debe ejecutarse en el hilo principal y bloquear otros hilos. Es por eso que el resultado se inicializa de inmediato.

Entonces, mi pregunta es ¿cómo puedo implementar la función que si el usuario adjunta el .get (), ese hilo en performSomeTask() debería ejecutarse en el hilo principal? de lo contrario en el fondo.

Nota: No te centres en devolver el resultado. Lo implementaré en Java Generics. Lo que quiero saber es cómo hacer que el código sea reutilizable para que cuando el usuario solo adjunte .get() se ejecute en el hilo principal. De lo contrario, ese mismo código debería ejecutarse en segundo plano. No quiero escribir código repetido.

Puede consultar la biblioteca existente.

  • AsyncTask : oficial de Android para realizar tareas en segundo plano.
  • ION - para descargar / subir archivos

Entonces, dos bibliotecas tienen la misma característica, y hay muchas más bibliotecas que hacen lo mismo, y yo quiero hacer lo mismo.

Será genial si alguien me da un pequeño ejemplo para esto.


(Espero que aclare con valores de retorno en los ejemplos anteriores) Así que este es un tipo de solución única para su tarea. Mira de cerca a la tarea en ejecución en el nuevo hilo. Necesitas iniciar tu acción en segundo plano ThreadPool ....

¡Nota! (También espero que clarifique con el uso de subprocesos en segundo plano. Por ejemplo, el uso de su código anterior con la función .execute () - no inicia un nuevo subproceso, sino simplemente una nueva tarea para ejecutar desde BlockingQueue en ThreadPool estático)

Entonces, ¿qué sigue? Al usar la función .get () para ejecutar la tarea en MainThread, necesita publicar esta tarea en el ciclo de acción actual. Y ayudarás a Handler y Looper. Y respondiendo a tu pregunta, debes saber, que solo tienes una forma de realizar esta tarea. Iniciar la acción en el subproceso en segundo plano utilizando el método .execute () e iniciar una nueva tarea en el controlador utilizando el método .get (). ¡Eso es todo!

Si desea conocer algunos ejemplos de realización, hay muchos tipos de soluciones. Acabo de publicar single utilizando Handler y HandlerThread para subrayar el trabajo de este ejemplo.

public class MyLibrary extend HandlerThread { private static Handler backgroundHandler; private static Handler foregroundHandler; private static MyLibrary myLibrary private MyLibrary () { super(MyLibrary.class.getSimpleName()); start(); } public static MyLibrary getInstance() { if (myLibrary == null) { synchronized (MyLibrary.class) { if (myLibrary == null) { myLibrary = new MyLibrary(); } } } return myLibrary; } public static WorkingTask with (Context context) { //Just update, if there are null if (foregroundHandler == null) { foregroundHandler = new Handler(context.getMainLooper); } if (backgroundHandler == null) { backgroundHandler = new Handler(getLooper); } return new WorkingTask(); } public void getBackgroundHandler () { return backgroundHandler; } public void getForegroundHandler () { return foregroundHandler; } } // .......... public class WorkingTask { private Runnable workingRunnable; public performTask (Runnable run) { this.workingRunnable = run; return this; } public void execute () { MyLibrary.getInstance().getBackgoundHandler() .postRunnable(workingRunnable) } public void get () { MyLibrary.getInstance().getForegroundHanlder() .postRunnable(workingRunnable) } }


No intente hacer estallar ninguna burbuja aquí, pero no solo estamos recreando java.util.concurrent.Executors , que ya es la mejor práctica de Android para usar en tareas concurrentes flexibles (es decir, gestión de hilos y controladores)

Desde: AsyncTask

AsyncTask está diseñado para ser una clase de ayuda en torno a Thread y Handler y no constituye un marco de subprocesamiento genérico. Se recomienda utilizar AsyncTasks para operaciones cortas (como mínimo, unos segundos). Si necesita mantener los subprocesos en ejecución durante largos períodos de tiempo, se recomienda encarecidamente que utilice las distintas API proporcionadas por el paquete java.util.concurrent, como Ejecutor, ThreadPoolExecutor y FutureTask.

Desde: java.util.concurrent.Executors

Fábrica y métodos de utilidad para las clases Executor, ExecutorService, ScheduledExecutorService, ThreadFactory y Callable definidas en este paquete. Esta clase es compatible con los siguientes tipos de métodos:

  • Métodos que crean y devuelven una configuración ExecutorService con ajustes de configuración comúnmente útiles.
  • Métodos que crean y devuelven un ScheduledExecutorService configurado con ajustes de configuración comúnmente útiles.
  • Métodos que crean y devuelven un ExecutorService "envuelto", que deshabilita la reconfiguración haciendo que los métodos específicos de la implementación sean inaccesibles.
  • Métodos que crean y devuelven un ThreadFactory que establece subprocesos recién creados a un estado conocido.
  • Métodos que crean y devuelven un Callable fuera de otras formas de cierre, por lo que se pueden usar en métodos de ejecución que requieren Callable.

Por ejemplo (y lo que creo que Fildor estaba tratando de conseguir):

//An Executor and a set of RunnableTasks to be executed Executor executor = anExecutor(); executor.execute(new RunnableTask1()); executor.execute(new RunnableTask2());

Los medios más simples de ejecución directa en el hilo de la persona que llama:

class DirectExecutor implements Executor { public void execute(Runnable r) { r.run(); } }

Esta no es una llamada asíncrona, pero se puede ejecutar fácilmente como una, y no solo como el hilo de fondo, aquí hay una versión que genera un nuevo hilo por tarea:

class ThreadPerTaskExecutor implements Executor { public void execute(Runnable r) { new Thread(r).start(); } }

Y puede imponer cualquier tipo de límite, como la ejecución en serie:

class SerialExecutor implements Executor { final Queue<Runnable> tasks = new ArrayDeque<>(); final Executor executor; Runnable active; SerialExecutor(Executor executor) { this.executor = executor; } public synchronized void execute(final Runnable r) { tasks.add(new Runnable() { public void run() { try { r.run(); } finally { scheduleNext(); } } }); if (active == null) { scheduleNext(); } } protected synchronized void scheduleNext() { if ((active = tasks.poll()) != null) { executor.execute(active); } } }

Todos estos son ejemplos de libros de texto, pero es fácil ver que, como ya está allí, no necesitamos volver a crear la rueda, especialmente cuando ya admite el tipo de envoltura que MoinKahn está tratando de lograr y ya es la mejor práctica.

Pensé que agregaría un enlace a la página de la interfaz del ejecutor de Oracle , para obtener más información sobre el manejo correcto de la concurrencia y sobre cómo ajustar los servicios del ejecutor.

Edición: Además, aquí hay un muy buen ejemplo de FutureTask que usa ThreadPoolExecutor en una respuesta detallada de Gray sobre eso.


Tienes que usar la clase de tarea futura para hacer la tarea en segundo plano.

1er escenario Si la tarea está en segundo plano, volverá usando el método de la interfaz de resultados.

Segundo escenario Si la tarea está en primer plano, devolverá la salida directamente a la clase de llamada.

Código de ejemplo para ejecutar ()

public void execute() { new Thread(new Runnable() { @Override public void run() { Future future = mExecutorService.submit(mCursorBinderTask); Log.d("asd", "onCreate: started "); while (true) { if (future.isDone()) { if (mResultListener != null) { try { mResultListener.onResult(future.get()); } catch (InterruptedException e) { mResultListener.onResult(null); } catch (ExecutionException e) { mResultListener.onResult(null); } } break; } } } }).start(); }

Código de ejemplo para obtener ()

public ArrayList<T> get() throws ExecutionException, InterruptedException { return mCursorBinderTask.call(); }