我希望有人能解釋我爲什麼失敗?從錯誤的線程+內部類叫..奇怪的行爲
我的活動有一個內部類,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