【发布时间】:2013-05-08 15:03:12
【问题描述】:
我想请人解释一下为什么会失败...
我的活动有一个内部类 AppHelper,它导出一个函数 setThrobber。为简单起见,我省略了所有的初始化代码等。
此函数 setThrobber 旨在在 UI 线程之外调用,通常在网络加载期间,以报告进度...然后,这些类使用内部类 AppHelper 和 setThrobber 方法从网络加载器执行此操作线程。
令我惊讶的是,第一种方法失败了(见最后的错误),第二种方法成功了。为什么第一个不在UI线程中执行而第二个是???更奇怪的是,在错误堆栈跟踪中,它看起来像是从 UI 线程调用的,即使 Android 抛出了 Called From Wrong Thread 异常。为什么从线程的角度来看两个代码块不等价?
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 (!!)
}
});
}
}
}
对比
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
}
}
}
第一种情况的Stack trace:
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 类在主 Activity 中被实例化,并被传递给 Activity 中的其他子类,使用 WeakReference 保持它(检查这不是问题)
使用失败的 AppHelper 的类会:
public void story_loadfonts(String jsonFonts) {
最后的 AppHelper appHelper=mWeakAppHelper.get(); // apphelper 存储在弱引用中
尝试 {
.
.
.
新线程(新可运行(){
@覆盖
公共无效运行(){
尝试 {
for (int i=0; i
【问题讨论】:
-
代码对我来说看起来不错。也许更多的代码会有所帮助
-
是的,它在我看来也不错!问题是,没有更多与该问题相关的代码。如果我只是切换 runUiThread 它可以完美运行,但我不知道有什么区别!
-
请分享实例化
AppHelper并调用该方法的代码。 -
嗨,tbkn!我正在发布该代码,但是为什么它会相关?问题的根源不是从 RunOnUiThread 开始吗?
-
出于兴趣,是NativeStory.java的第269行?
标签: android multithreading user-interface inner-classes