Android runOnUiThread / AsyncTask cannot resolve CalledFromWrongThreadException

I am working on an Android application and implement the ProgressBar using the AsyncTask class.

The problem is that on some devices this raises a "CalledFromWrongThreadException: only the source thread that created the view hierarchy can touch its views." in onPostExecute. On these devices, the problem occurs 100%. On other devices, it works fine.

public final class MyAsyncTask extends AsyncTask<String, Integer, String> { private ProgressBar progress; private ListActivity activity; public MyAsyncTask(ListActivity activity, ProgressBar progress) { this.progress = progress; this.activity = activity; } protected void onPreExecute() { this.progress.setVisibility(view.VISIBLE); } protected String doInBackground(String[] arg0) { // getting xml via httpClient return string; } protected void onPostExecute(String result) { this.progress.setVisibility(view.GONE); } 

I do not understand why onPostExecute does not start in the user interface thread on these specific devices.

Then I tried to call it using runOnUiThread to make sure that it works in the user interface thread.

 runOnUiThread(new Runnable() { @Override public void run() { ProgressBar progress = (ProgressBar)findViewById(R.id.some_view_progressbar); MyAsyncTask task = new MyAsyncTask(activity, progress); task.execute(); } } ); 

Even this did not solve the problem. The same exception is still happening.

From the log I confirmed that Thread.currentThread (). getId () is certainly different from the main application activity flow inside the handler.

I am stuck. Any advice would be appreciated.

NOTE. I edited the sample code (not the real code) above to fix the wrong method name and skip the "return string". I will add more information later.

+5
source share
3 answers

I don't see anything wrong with MyAsyncTask , but there are other things that can go wrong.

Running AsyncTask

From Android Docs

Threading Rules

There are several streaming rules that must be followed for this class to work properly:

  • The AsyncTask class must be loaded into the user interface thread. This is done automatically with JELLY_BEAN.
  • A task instance must be created in the user interface thread.
  • execute (Params ...) must be called in the user interface thread.
  • Do not call onPreExecute (), onPostExecute (Result), doInBackground (Params ...), onProgressUpdate (Progress ...) manually.
  • A task can be executed only once (when trying to execute a second execution, an exception will be thrown).

You do not show where you usually create the instance, and you complete the task, so make sure you do this in code that is already in the UI / main interface. Please note that the first dot with a marker may explain why this works for you on some devices and not on others.

Creating a view hierarchy

Message informs you

Only the source stream that created the view hierarchy can touch its views.

and you assume that this is because your async task (oddly enough) is trying to change the user interface in the background thread. However, it is possible that you will get this error, since an asynchronous task changes the user interface in the main thread, but the user interface ( ProgressBar ) was not created correctly in the first place.

See this question for an example of how you can erroneously create an idea about the wrong thread (nothing but the main thread) and get the same error.

More details

However, I would like to see exactly where you register the stream identifier and what values ​​you get. If you check my first two sentences and they do not solve your problem, we may need additional information.

You also mention Handler (?), But don’t show how and where you use it. Usually using AsyncTask eliminates the need to use Handler , so I'm a little worried about how you can use this.

Update

In the discussion in the comments below, it seems that the problem here is the one discussed in this question . Some code probably works in the background thread, first causing the AsyncTask class to load. The initial implementation (pre-Jelly Bean) of AsyncTask required loading the class into the main thread (as indicated in the Threading Rules above). A simple workaround is to add code to the main thread (for example, to Application#onCreate() ), which forces early deterministic loading of AsyncTask classes:

 Class.forName("android.os.AsyncTask"); 
+7
source

Make sure you call aysnctask.execute () only from the main thread.

+1
source

Write a handler in the user interface thread and call the handler from onPostExecute. This will solve the problem.

Something like that. Take a handler in the user interface thread (main thread):

 handler = new Handler(){ @Override public void handleMessage(Message msg) { //run on UI Thread } }; 

and call onPostExecute () as follows:

  handler.sendEmptyMessage(MSG); 
0
source

All Articles