Android AsyncTask onPostExecute disconnected from main ui thread

I have a problem with AsyncTask and onPostExecute. I find that onPostExecute runs on a different thread than the main ui thread that throws a CalledFromWrongThreadException when I change any views.

I started some logging to find out which streams on PreExecute, doInBackground and onPostExecute work. I would see such a result ...

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

I believe that the main identifier of the ui thread is 1, and I would expect both onPre and onPost to both be executed in thread 1. I am sure that you create and also call the execute method from the ui thread (for example, onCreate of a Events).

Another thing I noticed is that in subsequent async tasks, their onPostExecute method will be launched in the same thread as the previous async onPostExecute task (in this case, thread 18).

Right now, to get around this, I am wrapping code in my onPostExecute methods when calling runOnUiThread, but I think this is hacked and would like to get a real problem.

I have no ideas! Does anyone have an understanding? I am happy to answer any questions that may help with further investigation!

EDIT:

There are two ways to run asynchronous tasks in code. I wonder if the last of these examples causes anything strange?

 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!!! } } 

}

The above is similar to using AsyncTask's vanilla use, but I can still see that this question occurs even in simple cases like this. The following example uses the async task to perform other async tasks. Maybe there is something that I do not know about what happens when an asynchronous task is created that causes some strange behavior?

 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); } } } 

Perhaps what is happening here is just super weird, and not at all how asynchronous tasks should be used, since it would be nice to understand the essence of the problem.

Let me know if you need more context.

+7
source share
5 answers

I had the same problem and it turned out that the problem is related to using Flurry 3.2.1. However, the problem is not limited to the Flurry library.

The problem behind the scenes is the first (when the application loads for the first time) AsyncTask call from the looper thread, which is not the main UI thread. This call initializes the static sHandler variable in AsyncTask with an invalid stream identifier, and this identifier is then used in all subsequent AsyncTask $ onPostExecute () calls.

To solve this problem, I call an empty (without anything) AsyncTask when I first load the application, just to properly initialize AsyncTask.

+4
source

try using:

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

and write your code inside the run function

+1
source

AsyncTask is intended for use in the main thread. Your problem is the second case, and you call execute on SingleTask from the background thread. You call it in the doInBackground method for RunnerTask. OnPostExecute is then launched from backgroundthread RunnerTask

Two options for you.

1: Trash RunnerTask and execute SingleTasks from the main thread, all of them will be executed in parallel and you won’t know what ends first, but onPreExecute and onPostExecute are called in the main thread

2: Reset SingleTask and define them as Runnables, then you can run them sequentially in RunnerTask doInBackground. They will all work in the RunnerTask background thread in the order that you call Run. When it is completed, onPostExecute RunnerTask will be launched in the main thread.

+1
source

I just tried my code, and onPreExecute and onPostExecute run in the same thread, how do you get the thread id? try:

 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 it should be:

 new SomeAsyncTask().execute(); 

and

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

you are actually executing the SingleTask method from the RunnerTask doinbackground, which is incorrect, since asynctask should only be executed from the main thread. You need to rethink the logic that runs the SingleTasks collection from RunnerTask.

0
source

All Articles