我希望有人能解释我为什么失败?从错误的线程+内部类叫..奇怪的行为
我的活动有一个内部类,AppHelper,可导出函数setThrobber。为了简单起见,我省略了所有的初始化代码等。
此函数setThrobber是为了在UI线程之外调用,通常在网络加载期间报告进度......然后,这些类使用内部类AppHelper使用setThrobber方法从网络加载器线程执行此操作。
令我吃惊的是,第一种方法失败了(见最后的错误),第二种方法成功。为什么不是第一个在UI线程中执行的,第二个是?更奇怪的是,在错误堆栈跟踪看起来它是从UI线程调用的,即使Android抛出了“来自错误的线程”异常。为什么不是两个代码块都等同于线程的角度?
PD-我还尝试了一个handler.post(),结果相同! PD2- AppHelper类实例化在onCreate
在此先感谢!
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
}
}
}
的第一种情况的堆栈跟踪:
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)
要求提供补充代码:
的AppHelper类的主要内部实例化活动,并通过编辑在活动的其他子类,即保持与WeakReference的(检查,这是没有问题的)
使用失败做AppHelper的类:创建
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;
}
}
代码看起来不错。也许更多的代码会有帮助 – Blackbelt 2013-05-08 15:07:00
是的,它也看起来很好!事情是,这个问题没有太多相关的代码。如果我只是切换runUiThread它完美的作品,但我不知道区别! – rupps 2013-05-08 15:08:58
请分享实例化AppHelper并调用方法的代码。 – tbkn23 2013-05-08 15:21:35