Cómo utilizar correctamente AsyncTask durante SyncAdapter onPerformSync
-
29-10-2019 - |
Pregunta
He estado recibiendo una gran cantidad de informes de errores de usuarios informados de los cuadros de diálogo de cierre forzado que indican algo como lo siguiente:
java.lang.ExceptionInInitializerError
at com.MyRequest.execute(MyRequest.java:59)
at org.nsdev.MySyncAdapter.onPerformSync(MySyncAdapter.java:90)
at android.content.AbstractThreadedSyncAdapter$SyncThread.run(AbstractThreadedSyncAdapter.java:164)
Caused by: java.lang.RuntimeException:
Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:121)
at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
at android.os.AsyncTask.<clinit>(AsyncTask.java:152)
Ahora, he intentado averiguar cuál es la mejor forma de resolver este problema.Dentro de mi implementación onPerformSync, estoy creando una serie de AsyncTasks y ejecutándolas.Sospecho que mi problema es que no estoy esperando a que se completen estas tareas antes de regresar de onPerformSync.Intenté hacer lo siguiente:
Looper.prepare();
// Execute async tasks
Looper.loop();
Y luego configuro un contador y cuando ese contador disminuye a cero, llamo a Looper.myLooper (). quit () dentro de la devolución de llamada desde las tareas asíncronas.
Pero hacer esto hace que mi aplicación se bloquee aún más con el siguiente error de tiempo de ejecución:
java.lang.RuntimeException: Main thread not allowed to quit
at android.os.MessageQueue.enqueueMessage(MessageQueue.java:175)
at android.os.Looper.quit(Looper.java:173)
at org.nsdev.MySyncAdapter$1.requestFinished(MySyncAdapter.java:89)
at com.MyAsyncTask.onPostExecute(MyAsyncTask.java:84)
at android.os.AsyncTask.finish(AsyncTask.java:417)
at android.os.AsyncTask.access$300(AsyncTask.java:127)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:429)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4627)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
at dalvik.system.NativeStart.main(Native Method)
¿Alguna idea de cómo realizar correctamente mi sincronización?
Solución
Sé que esta publicación es antigua, pero para otras personas que se encuentran con este hilo, ¿qué tal si no llaman a looper.quit () en el hilo principal?Lo siguiente funciona para mí desde un Servicio SyncAdpater que genera varias AsyncTasks, aunque puede haber otras razones para no hacer esto en términos de rendimiento ...
Handler h = new Handler(Looper.getMainLooper());
h.post(new Runnable() {
public void run() {
// AsyncTask... execute();
}
});
Otros consejos
En realidad, no puedes.AsyncTask usa el hilo principal de la interfaz de usuario y se basa en Handler y Looper, que no está disponible allí.Use la implementación de Thread pura, AsyncTask debe usarse solo en las actividades.
La respuesta de abloc soluciona el problema, pero el problema con esta solución es que la UI se congela, este problema está presente en Android 2.2 y Android 2.3.El truco que encontré fue invocar un constructor de AsyncTask en mi clase SyncAdapter
y usé Looper.prepare()
:
/**
* Constructor. Obtains handle to content resolver for later use.
*/
public SyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
mHandler = new Handler();
//Crear un dummy AsyncTask
new AsyncTask<Void, Void,String>() {
@Override
protected String doInBackground(Void... params) {
return null;
}
}.execute(null,null);
}