Join FlipAndroid.COM Telegram Group: https://t.me/joinchat/F_aqThGkhwcLzmI49vKAiw


Android AsyncTask onPostExecute fuera del hilo principal de ui

Tengo un problema con AsyncTask y onPostExecute. Estoy encontrando que onPostExecute está ejecutando en un hilo diferente que el hilo principal de ui, que está causando un CalledFromWrongThreadException a suceder cuando modifico cualquier opinión.

Puse en algún registro para ver lo que los hilos de rosca onPreExecute, doInBackground, y onPostExecute están funcionando encendido. Vería un resultado como este …

onPreExecute ThreadId: 1 doInBackground ThreadId: 25 onPostExecute ThreadId: 18 

Creo que el ID principal del hilo ui es 1 y esperaría tanto onPre como onPost para ejecutar en el hilo 1. Estoy asegurándome de crear y también llamar al método execute desde el hilo ui (por ejemplo en onCreate de una Actividad).

Otra cosa a notar que he notado es que las tareas asíncronas posteriores ejecutarán su método onPostExecute en el mismo subproceso que los métodos onPostExecute de la tarea async anterior (en este caso el subproceso 18).

En este momento, para evitar esto, estoy envolviendo el código en mis métodos onPostExecute en una llamada a runOnUiThread, pero creo que esto es hacky y me gustaría llegar al problema real.

¡Se me acabaron las ideas! ¿Alguien tiene alguna idea? ¡Estoy feliz de responder cualquier pregunta que pudiera ayudar con más investigación!

EDITAR:

Hay dos maneras en que se ejecutan tareas asíncronas en el código. Me pregunto si este último en estos ejemplos está causando algo extraño que suceda?

 public class SomeActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main_layout); new SomeAsyncTask().execute(); } private class SomeAsyncTask extends AsyncTask<String, Void, Integer> { @Override public void onPreExecute() { Thread.currentThread().getId() // 1 //Show a dialog } @Override public Integer doInBackground(String... params) { Thread.currentThread().getId() // 25 return 0; } @Override public void onPostExecute(Integer result) { Thread.currentThread().getId() // 18 //hide dialog //update text view -> CalledFromWrongThreadException!!! } } 

}

Lo anterior parece un uso de vainilla de AsyncTask, pero todavía veo este problema ocurriendo incluso en casos simples como este. El siguiente ejemplo utiliza una tarea asíncrona para ejecutar otras tareas asíncronas. Tal vez hay algo que no sé acerca de lo que sucede cuando se construye una tarea asíncrona que está causando algún comportamiento extraño?

 public class SomeActivity extends Activity implements TaskRunner.OnFinishListener { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main_layout); TaskRunner taskRunner = new TaskRunner(); taskRunner.setOnFinishListener(this); taskRunner.addTask(new SingleTask()); taskRunner.addTask(new SingleTask()); taskRunner.execute(); } @Override public void onTaskFinish(List<Integer> results) { //Thread id is 18 when it should be 1 //do something to a view - CalledFromWrongThreadException!! } } //In a different file public class SingleTask extends AsyncTask<String, Void, Integer> { //This is a an async task so we can run it separately as an asynctask //Or run it on whatever thread runnerExecute is called on @Override public Integer doInBackground(String... params) { return runnerExecute(params); } //Can be called outside of doInBackground public Integer runnerExecute(String... params) { //some long running task return 0; } } //In a different file public class TaskRunner { private List<SingleTask> tasks; private OnFinishListener onFinishListener; public interface OnFinishListener { public void onTaskFinish(List<Integer> results); } public TaskRunner() { this.tasks = new ArrayList<SingleTask>(); } public void setOnFinishListener(OnFinishListener listener) { this.onFinishListener = listener; } public void addTask(SingleTask task) { tasks.add(task); } public void executeTasks() { new RunnerTask().execute((SingleTask[]) tasks.toArray()); } //Calls the runnerExecute method on each SingleTask private class RunnerTask extends AsyncTask<SingleTask, Integer, List<Integer>> { @Override public void onPreExecute() { //Runs on thread 1 } @Override public List<Integer> doInBackground(SingleTask... params) { //Runs on arbitrary thread List<Integer> results = new ArrayList<Integer>(); for(SingleTask task : params) { int result =task.runnerExecute(task.getParams()); results.add(result); } return results; } @Override public void onPostExecute(List<Integer> results) { //Runs on thread 18 onFinishListener.onTaskFinish(results); } } } 

Tal vez lo que está pasando aquí es simplemente muy extraño, y no en absoluto cómo las tareas asíncronas están destinadas a ser utilizado, de cualquier manera sería bueno llegar al fondo del problema.

Déjame saber si necesitas más contexto.

  • Proveedores de contenido multiproceso sincronizados a uno predeterminado
  • Actualizar interfaz de usuario mientras trabaja en el fondo
  • Handler.sendMessageDelayed (msg, delay) no funciona correctamente
  • La mejor manera de ejecutar el método asincrónicamente en Android (compacto y correcto)
  • ¿Los hilos son lo suficientemente fiables para calcular segundos?
  • Pruebas de unidad de Android con múltiples subprocesos
  • Android - Prevenga la pantalla blanca al inicio
  • Diferencia real entre AsyncTask y Thread
  • 5 Solutions collect form web for “Android AsyncTask onPostExecute fuera del hilo principal de ui”

    He estado experimentando el mismo problema y resultó que el problema estaba utilizando Flurry 3.2.1. Sin embargo, la cuestión no se limita a la biblioteca Flurry.

    La cuestión detrás de las escenas es tener la primera vez (cuando la aplicación se carga por primera vez) AsyncTask llamada de un hilo looper que no es el hilo principal de interfaz de usuario. Esta llamada inicializa una variable estática de sHandler en AsyncTask al identificador de subproceso incorrecto y, a continuación, se utiliza en todas las llamadas AsyncTask $ onPostExecute () posteriores.

    Para resolver el problema, llamo un AsyncTask vacío (no hacer nada) en la primera carga de la aplicación, solo para inicializar AsyncTask correctamente.

    Intenta usar:

     getBaseContext().runOnUiThread(new Runnable() { @override public void run() { } }); 

    Y escribir su código dentro de la función de run

    El AsyncTask está diseñado para ser utilizado desde el hilo principal. Su problema es el segundo caso, y es que usted llama a ejecutar en el SingleTask de un hilo de fondo. Lo llama en el método doInBackground de RunnerTask. El onPostExecute se ejecuta a partir de la línea de fondo de RunnerTask

    Dos opciones para usted.

    1: Trash RunnerTask, y ejecutar las SingleTasks de tu hilo principal, todos correrán en parallell y no sabrás que termina primero, pero onPreExecute y onPostExecute se llama en el hilo principal

    2: Trash the SingleTask y definirlos como Runnables en su lugar, entonces puede ejecutarlos en secuencia en el DoInBackground del RunnerTask. Todos se ejecutarán en el subproceso de fondo de RunnerTask, en el orden que se llama Ejecutar. Cuando se termina, onPostExecute de RunnerTask se ejecuta en el subproceso principal.

    Acabo de probar su código y onPreExecute y onPostExecute se ejecuta en el mismo hilo, ¿cómo se emite el id de hilo? tratar:

     Log.d("THREADTEST","PRE"+Long.toString(Thread.currentThread().getId())); Log.d("THREADTEST","BACKGROUND"+Long.toString(Thread.currentThread().getId())); Log.d("THREADTEST","POST"+Long.toString(Thread.currentThread().getId())); 

    PS debe ser:

     new SomeAsyncTask().execute(); 

    y

     private class SomeAsyncTask extends AsyncTask<String, Void, Integer> { ... } 

    En realidad está ejecutando la SingleTask desde el método doinbackground de RunnerTask que es incorrecto, ya que asynctask debe ejecutarse a partir de un subproceso principal solamente. Necesita revisar la lógica que ejecuta el conjunto de SingleTasks de RunnerTask.

    FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.