I'd like to someone explain me why this fails...
My activity has an inner class, AppHelper, that exports a function setThrobber. For simplicity I have omitted all the init code, etc..
This function setThrobber is meant to be called outside of the UI thread, normally during network loads, to report progress... Then, the classes use the inner class AppHelper with the method setThrobber to do so, from the network-loader thread.
To my surprise, the first approach fails (see error at the end) and the second succeeds. Why isn't the first one executed in the UI thread and the second one is??? More strange is, in the error stack trace looks like it IS called from the UI thread, even though Android throws the Called From Wrong Thread exception. Why are not both code chunks equivalent from the thread point of view?
PD- I also tried a handler.post() with the same result! PD2- The AppHelper class is instantiated inside onCreate
Thanks in advance !!
public class MyApplication extends Activity {
private ProgressDialog progressDialog;
void setThrobber_internal (String message) {
progressDialog.setMessage(message);
}
public class AppHelper {
public setThrobber(final String msg) {
MyApplication.this.runOnUiThread(new Runnable() {
@Override
public void run() {
setThrobber_internal(msg);
// This throws CalledFromWrongThread (!!)
}
});
}
}
}
VERSUS
public class MyApplication extends Activity {
private ProgressDialog progressDialog;
private void setThrobber_internal(final String msg) {
// runUiThread here instead of in inner class wrapper
runOnUiThread(new Runnable() {
@Override
public void run() {
progressDialog.setMessage(msg);
}
});
}
public class AppHelper {
public void setThrobber(final String msg) {
setThrobber_internal(msg); // this works OK
}
}
}
The Stack trace of the first situation:
E/AndroidRuntime(17677): FATAL EXCEPTION: main
E/AndroidRuntime(17677): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
E/AndroidRuntime(17677): at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:4039)
E/AndroidRuntime(17677): at android.view.ViewRootImpl.invalidateChild(ViewRootImpl.java:722)
E/AndroidRuntime(17677): at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:771)
E/AndroidRuntime(17677): at android.view.ViewGroup.invalidateChild(ViewGroup.java:4005)
E/AndroidRuntime(17677): at android.view.View.invalidate(View.java:8576)
E/AndroidRuntime(17677): at android.view.View.invalidate(View.java:8527)
E/AndroidRuntime(17677): at android.widget.TextView.checkForRelayout(TextView.java:6760)
E/AndroidRuntime(17677): at android.widget.TextView.setText(TextView.java:3306)
E/AndroidRuntime(17677): at android.widget.TextView.setText(TextView.java:3162)
E/AndroidRuntime(17677): at android.widget.TextView.setText(TextView.java:3137)
E/AndroidRuntime(17677): at com.android.internal.app.AlertController.setMessage(AlertController.java:261)
E/AndroidRuntime(17677): at android.app.AlertDialog.setMessage(AlertDialog.java:185)
E/AndroidRuntime(17677): at android.app.ProgressDialog.setMessage(ProgressDialog.java:314)
----------------------------------
E/AndroidRuntime(17677): at com.regaliz.libneo.NativeStory.setThrobber_internal(NativeStory.java:269)
E/AndroidRuntime(17677): at com.regaliz.libneo.NativeStory$AppHelper$8.run(NativeStory.java:865)
----------------------------------
E/AndroidRuntime(17677): at android.os.Handler.handleCallback(Handler.java:605)
E/AndroidRuntime(17677): at android.os.Handler.dispatchMessage(Handler.java:92)
E/AndroidRuntime(17677): at android.os.Looper.loop(Looper.java:137)
Request for additional code:
The AppHelper class is instantiated inside the main activity, and is passed to other child classes in the activity, that keep it with a WeakReference (checked this is not the problem)
The classes that use the AppHelper that fails do:
public void story_loadfonts(String jsonFonts) { final AppHelper appHelper=mWeakAppHelper.get(); // apphelper stored in a weak ref try { . . . new Thread(new Runnable() { @Override public void run() { try { for (int i=0; i<NUMFONTS; i++) { load_font_from_network(i); appHelper.setThrobber("LOADING FONT "+i+"/"+NUMFONTS); } } catch (JSONException e) { e.printStackTrace(); } } }).start(); } catch (Exception e) { return; } }