Práctica recomendada para iniciar AsyncTask desde la vista personalizada
Es bastante común generar un hilo de cálculo que consume tiempo. Posteriormente, necesitamos actualizar Activity
o Fragment
con resultado computacional.
Todo el tiempo, estoy siguiendo las siguientes pautas. Funciona bien para mí hasta ahora.
- Android: pasa un objeto JSON entre fragmentos
- Las pestañas de TabLayout no se muestran
- Detener evento táctil de ser interceptado por ViewPager si hay evento táctil en la vista web
- Obtener datos del modelo de clase al fragmento
- ViewPager en TabFragment no se carga por segunda vez
AsyncTask necesita un fragmento de UI onPostExecute
- Use
setRetainInstance(true)
fragmento sin UI. - Utilice la técnica
setTargetFragment
ygetTargetFragment
- Consulte https://stackoverflow.com/a/12303649/72437
AsyncTask necesita ejecutar OnPostExecute Actividad de la interfaz de usuario
- Use
setRetainInstance(true)
fragmento sin UI. - Utilice
onAttach
yonDetach
para almacenar referencia aActivity
. Google parece no alentar el uso degetActivity
. Http://developer.android.com/guide/components/fragments.html - Consulte https://stackoverflow.com/a/16305029/72437
Sin embargo, ¿qué tal el caso de una clase derivada de View
? Planeo lanzar AsyncTask
desde la View
personalizada. Sin embargo, ¿cómo puedo onPostExecute
volver a la View
?
La razón por la que lo estoy pidiendo es, en mi vista personalizada, cierto evento táctil lo activará para volver a dibujarse con un nuevo mapa de bits. Generar el nuevo mapa de bits requiere mucho tiempo. Por lo tanto, planeo lanzar un AsyncTask, para generar dicho mapa de bits, y pasar de nuevo a la vista personalizada. Sin embargo, el cambio de configuración puede provocar que se vuelva a crear la vista personalizada. Por lo tanto, necesito asegurar mi AsyncTask puede tener la referencia correcta de la visión sobre onPostExecute
.
- Los fragmentos ViewPager hacen referencia al mismo RecyclerView y / o Adapter
- Cómo implementar fragmento resizableable por arrastre de usuario (no animación de transición predefinida)
- Mejores prácticas de fragmentos
- ViewPager establece la página actual por programación
- Android gestiona fragmentos de actividad elegantemente
- No se puede establecer la propiedad en un fragmento con varias instancias
- ¿Cómo mostrar el teclado virtual perfectamente en fragmento en Android?
- Fragmento sobre otro fragmento
Suponiendo que está utilizando AsyncTask
sólo para las operaciones relacionadas con el dibujo (de lo contrario debería revisar su lógica – como sugieren los comentarios), puede crear AsyncTask
directamente en su clase de View
personalizada:
class MyView extends View { private MyAsyncTask currentTask = null; // View details @Override public void onAttachedToWindow() { currentTask = new MyAsyncTask(this); currentTask.execute(); } @Override public void onDetachedFromWindow() { super.onDetachedFromWindow(); if (currentTask != null) { currentTask.cancel(true); currentTask = null; } } static class MyAsyncTask extends AsyncTask<Void, Void, Bitmap> { private WeakReference<MyView> viewRef; MyAsyncTask(MyView view) { viewRef = new WeakReference<>(view); } // background task implementation @Override public void onPostExecute(Bitmap bitmap) { MyView view = viewRef.get(); if (view == null) { return; } // you now can safely update your view - we're on UI thread } } }
Así es como se vería la implementación segura. Tiene algunas desventajas y partes importantes:
- En ningún momento su
AsyncTask
debería mantener una referencia fuerte aView
(por eso la clase es declarada comostatic
y tieneWeakReference
enView
) - Cuando ya no te interesa el resultado de
AsyncTask
, cancela - Esta implementación simplemente
AsyncTask
resultado posiblemente útil deAsyncTask
cancelado. Si ese es el problema, sugeriría eliminarAsyncTask
deView
completamente y buscar otras soluciones (Executor
separado oHandlerThread
).
También onPostExecute
de AsyncTask
será llamado desde el mismo thread looper que lo lanzó (en su caso, que es el hilo principal, por lo que no importa si se inicia desde la Activity
o View
, o en cualquier otro lugar, todo depende de lo difícil que sería Para gestionar esas tareas).
Te daré una idea general de que puedes seguir adelante aplicándote en cualquier lugar que necesites (incluyendo desde Thread
o ThreadExecutor
(en lugar de confiar sólo en AsyncTask);
Puede usar directamente una biblioteca para manejar events
, donde los eventos se distribuyen en un "bus" común y cualquier clase que desee puede registrarse en el bus y escuchar esos eventos:
Y para eso me referiré a Otto, funciona bien y es muy potente: http://square.github.io/otto/
Alternativamente puede implementarlo usted mismo con el LocalBroadcastManager
https://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html como este:
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(context)
<que es para obtener una referencia a la misma.
OnEventComplete: (sucede en su hilo o AsyncTask
Intent i = new Intent("DOWNLOAD_COMPLETE"); // ps. feel free to attach extras to the intent, in order to pass data back to your activity/fragment/view lbm.sendBroadcast(i);
Luego en tu actividad / fragmento / vista creas un receptor
BroadcastReceiver receiver = new BroadcastReceiver(){ @Override public void onReceive (Context context, Intent intent){ // feel free to read the extras from the intent with data here and update your view } };
OnStartListening:
lbm.registerReceiver(receiver, new IntentFilter("DOWNLOAD_COMPLETE"));
OnStopListening:
lbm.unregisterReceiver(receiver);
Entonces DEBE comenzar y dejar de escuchar durante onStart
/ onStop
o onResume
/ onPause
o onAttachedToWindow
/ onDetachedFromWindow
(para vistas)
- Diferentes valores de giroscopio en celulares cromados móviles y safari
- Cómo crear un proyecto de plantilla para Android Studio