I have an app in production for a few weeks, using ACRA, and I had zero errors until one strange error reported today.
I’ve got:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
coming from this method in the stack trace (retraced):
at my.app.CountdownFragment$1.void onPostExecute(java.lang.Object)(SourceFile:1)
And this is the relevant source snippet:
private void addInstructionsIfNeeded() {
if (S.sDisplayAssist) {
new AsyncTask<String, Void, String>() {
@Override
protected String doInBackground(String... params) {
return null;
}
/*
* runs on the ui thread
*/
protected void onPostExecute(String result) {
Activity a = getActivity();
if (S.sHelpEnabled && a != null) {
in = new InstructionsView(a.getApplicationContext());
RelativeLayout mv = (RelativeLayout) a
.findViewById(R.id.main_place);
mv.addView(in.prepareView());
}
};
}.execute("");
}
}
Where addInstructionsIfNeeded() is called from a handler dispatched message (the UI thead).
onPostExecute()runs on the UI thread, so why I’ve got “wrong thread”?- This code ran already on more than 150 devices, and more than 100000 times (according to Flurry), and never had this error.
- The originating device is Samsung SGH-I997 running SDK 4.0.4
My question is: How could it be?
EDIT:
This all happens in a fragment
i was suffering from the same problem, this is another android framework bug…
what is happening:
in certain circumstances an application can have more than one “looper” and therefore more than one “UI thread”
–side note– i am using the term “UI thread” in the loosest of senses in this answer, since when people say “UI thread” they usually mean main or entry thread, Android like many of other OS before it, allow for for multiple message pumps (called a
Looperin Android, see: http://en.wikipedia.org/wiki/Event_loop) for different UI trees, as such android for all intents and purposes is capable of running more than one “UI thread” in certain circumstances and using that term leads to rampant ambiguities… –end side note–this means:
since an application can have more than one “UI thread” and an
AsyncTaskalways “Runs on the UI thread” [ref], someone decided [poorly] that instead of the AsyncTask always running on its creation thread (which in 99.999999% of cases would be the correct “UI thread”) they decided to use hocus pocus (or a poorly crafted shortcut, you decide) to execute on the “main looper”..example:
if called from the bad situation described above the output will look something like this:
that’s a huge FAIL for
AsyncTaskas shown this can be mitigated using a
Handler.post(Runnable)in my specific case the duality of my “UI thread” situation was caused by the fact that I was creating a dialog in response to a JavaScript interface method called from aWebView, basically: theWebViewhad its own “UI thread” and that was the one that i was currently running on..from what i can tell (without really caring about or reading into it too much) it seems that the
AsyncTaskclass’ callback methods in general run off a single statically instantiated handler (see: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.3_r1/android/os/AsyncTask.java#AsyncTask.0sHandler), which means that it is always going to execute on the “main thread” or “entry thread” which they incorrectly refer to as the “UI thread” (which is presumed as any thread where UI interactions take place, eg. multiple threads in this case) this is both shoddy craftsmanship and shoddy documentation from the android team… weak sauce, the sauce is weakhope this helps you -ck