programacion - manual de android en pdf
Comprueba si todas las AsyncTasks han finalizado. (10)
Tengo 3 AsyncTasks
y 1 ProgressBar
. Quiero que cuando se ejecute alguna de las tareas, la barra de progreso esté visible y cuando todas hayan terminado, la barra de progreso sea invisible.
En Java, está ExecutorService::isTerminated
para verificar si todos los ejecutables han finalizado pero Android no lo tiene.
Actualización: 3 tareas se ejecutan al mismo tiempo.
Figura.
: -? Creo que es sólo un truco. devolverá algún mensaje en onPostExecute
de cada Asyntask
y lo comparará. (este mensaje puede contener una hora, por ejemplo)
Bonito gráfico. Pero me temo que no hay ningún mecanismo para esto. Tendrás que implementarlo por ti mismo. Hay pocas soluciones que podrías usar -
- Mantenga una referencia a las 3 tareas. Cuando finalice la tarea, compruebe si las otras dos tareas también se completaron, en caso afirmativo, cierre el cuadro de diálogo de progreso si no, espere a que finalice alguna otra tarea y vuelva a verificar. Asegúrate de liberar las referencias cuando hayas terminado.
- Si no quieres mantener una tienda de referencia un contador. Cuando finalice la tarea, incremente el contador y verifique si es igual a 3. Si todas las tareas terminaron y terminó. Si implementa esto, asegúrese de sincronizar el acceso al contador.
Bueno, como ya sabe cuando finaliza una AsyncTask
(cuando se llama onPostExecute
): una solución podría ser crear un método setProgressBarVisible()
que mantenga un contador y cuando los primeros conjuntos llamados sean visibles, y un método setProgressBarInvisible()
que disminuya el contador y cuándo cero establece la barra de progreso invisible.
Esta es una pregunta común cuando desea ejecutar un montón de AsynTasks en un THREAD_POOL_EXECUTOR. Es mucho más rápido que si solo llama a .execute()
y todas sus tareas se realizan una por una. Por lo tanto, si tiene varios trabajos y los objetos no dependen de los demás estados, intente ejecutarlos en un grupo de subprocesos.
Pero la pregunta es: ¿cómo sé que todas mis tareas están terminadas?
No hay métodos integrados en AsyncTask, por lo que debe hacer una pequeña solución.
En mi caso, agregué un campo Hashmap estático a mi clase de Asynctask para realizar un seguimiento de todas las tareas iniciadas y finalizadas. Como beneficio adicional de un mapa, siempre puedo saber qué tarea está actualmente en progreso.
private static HashMap<Uri, Boolean> mapOfAttachmentTasks = new HashMap<>();
y ad simple tres métodos para acceder a este mapa. Importante: deben estar sincronizados.
public static synchronized void addTask(Uri uri){
mapOfAttachmentTasks.put(uri, true);
}
public static synchronized void removeTask(Uri uri){
mapOfAttachmentTasks.remove(uri);
}
public static synchronized boolean isTasksEmpty(){
return mapOfAttachmentTasks.isEmpty();
}
Desea agregar un nuevo elemento al mapa de seguimiento en un constructor de AsyncTask y eliminarlo en onPostExecute ():
public AttachmentTask(Uri uri) {
this.uri = uri;
addTask(uri);
}
@Override
protected void onPostExecute(Attachment attachment) {
removeTask(uri);
if(isTasksEmpty())
EventBus.getDefault().post(new AttachmentsTaskFinishedEvent(attachment));
}
Cada vez que una tarea finaliza, llama a PostEexecute y usted verifica si fue la última tarea. Si no le quedan tareas, envíe una señal de que ha terminado.
Ahora, aquí usé EventBus para enviar eventos a mi Fragmento, pero puedes usar una devolución de llamada. En este caso, debe crear una interfaz con el método de devolución de llamada, su Fragmento (cualquiera de los componentes de la IU que están esperando el evento) debe implementar esta interfaz y tener ese método. Luego, en el constructor de AsyncTask, obtienes tu Fragmento como un argumento y mantienes una referencia a él, para que puedas llamar a su método de devolución de llamada cuando todo esté listo.
Pero no me gusta ese enfoque. Primero, debe mantener la referencia de su Fragmento (o cualquier otra IU) en un envoltorio de WeakReference porque obtendrá una pérdida de memoria cuando su fragmento esté muerto (pero aún se conservará en la memoria porque su AsyncTask tiene su referencia). También necesitarías hacer muchos cheques y se verá algo así:
private boolean isAlive() {
return mFragmentWeakReference != null
&& mFragmentWeakReference.get() != null
&& mFragmentWeakReference.get().isAdded()
&& mFragmentWeakReference.get().getActivity() != null
&& !mFragmentWeakReference.get().getActivity().isFinishing();
Sí, en producción debes ser un poco paranoico y hacer todos estos controles :)
Por eso puedes usar EventBus y si tu interfaz de usuario está muerta, lo que sea.
Intente utilizar AsyncTask.getStatus (). Esto funciona perfectamente bien. Consulte el código de ejemplo a continuación.
List<AsyncTask<String, String, String>> asyncTasks = new ArrayList<AsyncTask<String, String, String>>();
AsyncTask<String, String, String> asyncTask1 = new uploadTask().execute(string);
AsyncTask<String, String, String> asyncTask2 = new downloadTask().execute(string);
AsyncTask<String, String, String> asyncTask3 = new createTask().execute(string);
asyncTasks.add(asyncTask1);
asyncTasks.add(asyncTask2);
asyncTasks.add(asyncTask3);
Más tarde puede hacer un bucle en AsyncTaskList y buscar el estado de cada tarea como se muestra a continuación.
for(int i=0;i<asyncTasks.size();i++){
AsyncTask<String, String, String> asyncTaskItem = (AsyncTask<String, String, String>)asyncTasks.get(i);
// getStatus() would return PENDING,RUNNING,FINISHED statuses
String status = asyncTaskItem.getStatus().toString();
//if status is FINISHED for all the 3 async tasks, hide the progressbar
}
Se introdujo un soporte oficial de CompletableFuture desde el nivel 24 de API.
También está disponible en Java 8 here .
Se puede usar simplemente usar algo como:
taskA.thenCombine(taskB).thenCombine(taskC)
Simplemente lo notificaría en onPostExecute()
, refiérase a onPostExecute y 4 pasos en el documento para obtener más detalles y puede usar EventBus
para hacer algunas suscripciones.
Una solución simple sería usar tres variables booleanas, una para cada AsyncTask y luego verificarlas en consecuencia.
Un mejor enfoque sería crear una clase separada que extienda AsynTask y defina una interfaz de devolución de llamada que se activa en onPostExecute.
crear un campo para mantener todas las tareas:
private ArrayList<HtmlDownloaderTask> mTasks;
Comience sus tareas de esta manera:
HtmlDownloaderTask = new HtmlDownloaderTask(page.getHtml());
task.execute(page.getUrl());
//if you want parallel execution try this:
//task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,page.getUrl());
mTasks.add(task);
en el onPostExecute de MyAsyncTask:
int unfinishedTasks = 0;
for (HtmlDownloaderTask myDT : mTasks){
if(!(myDT.getStatus() == AsyncTask.Status.FINISHED)){
unfinishedTasks++;
}
}
if (unfinishedTasks == 1){
//We are all done. 1 Because its the current one that hasnt finished post execute
callWhateverMethod();
}
prueba esto, tal vez pueda ayudarte ...
final ImageUploader _upload = new ImageUploader();
_upload.setValue(getApplicationContext(), _imagepath, _urlPHP);
_upload.execute();
Runnable _run;
Handler _h2;
_run = new Runnable() {
public void run() {
_h2 = new Handler();
_h2.postDelayed(this, 1000);
Toast.makeText(getApplicationContext(), "not finished", Toast.LENGTH_LONG).show();
if (_upload.getStatus() == AsyncTask.Status.FINISHED) {
Toast.makeText(getApplicationContext(), "finished", Toast.LENGTH_LONG).show();
_h2.removeCallbacks(_run);
}
}
};
_h2 = new Handler();
_h2.postDelayed(_run, 1);