Sto riscontrando un problema con AsyncTask e onPostExecute. Sto scoprendo che onPostExecute è in esecuzione su un thread diverso rispetto al thread ui principale, il che sta causando un'eccezione CalledFromWrongThreadException quando si modifica qualsiasi vista.Android AsyncTask onPostExecute off del thread ui principale
Inserisco alcune registrazioni per vedere quali thread suPreExecute, doInBackground e onPostExecute sono in esecuzione. Vorrei vedere un risultato come questo ...
onPreExecute ThreadId: 1
doInBackground ThreadId: 25
onPostExecute ThreadId: 18
Credo che il thread dell'interfaccia utente principale id è 1 e mi aspetto sia onPre e onpost sia per eseguire sul filo 1. sto facendo in modo di creare e anche chiamare il metodo execute dal thread ui (ad esempio in onCreate di un'attività).
Un'altra cosa da notare che ho notato è che in seguito le attività asincrone eseguiranno il loro metodo onPostExecute sullo stesso thread dei precedenti task asincroni sui metodi PostExecute (in questo caso il thread 18).
In questo momento, per aggirare questo problema, ho inserito il codice nei miei metodi onPostExecute in una chiamata a runOnUiThread, ma penso che questo sia hacky e vorrei ottenere il vero problema.
Sono fuori di idee! Qualcuno ha qualche intuizione? Sono felice di rispondere a qualsiasi domanda che potrebbe aiutarmi con ulteriori indagini!
EDIT:
Ci sono due modi che asincrone compiti sono in esecuzione nel codice. Mi chiedo se il secondo in questi esempi sta causando qualcosa di strano che accada?
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!!!
}
}
}
Quanto sopra sembra un uso vaniglia AsyncTask, ma ancora vedono questo problema si verifica anche nei casi più semplici come questo. Il prossimo esempio usa un'attività asincrona per eseguire altre attività asincrone. Forse c'è qualcosa che non so su cosa succede quando viene creato un task asincrono che sta causando un comportamento strano?
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);
}
}
}
Forse quello che sta succedendo qui è solo super strano, e non è affatto come asincrona compiti sono destinati ad essere utilizzati, in entrambi i casi sarebbe bello per andare a fondo della questione.
Fatemi sapere se avete bisogno di altro contesto.
Puoi mostrare il codice rilevante? – Eric
Non stai andando ad un altro 'Activity' prima che' AsyncTask' sia finito, vero? – codeMagic
No, attendo fino al completamento dell'account async e quindi avvio un'attività in onPostExecuteMethod. Aggiungerò del codice rilevante alla mia domanda. – fxfilmxf