1. 程式人生 > >bug_ _ android.view.WindowManager$BadTokenException: Unable to add window -- token

bug_ _ android.view.WindowManager$BadTokenException: Unable to add window -- token

運行 問題 彈出 跳轉 不存在 ber 需要 順序 tab

android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@41791b20 is not valid; is your activity running?
at android.view.ViewRootImpl.setView(ViewRootImpl.java:546)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:302)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:216)
at android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.java:141)
at android.view.Window$LocalWindowManager.addView(Window.java:537)
at android.app.Dialog.show(Dialog.java:278)
at android.app.AlertDialog$Builder.show(AlertDialog.java:991)
at android.widget.TextView.onTouchEvent(TextView.java:8430)
at android.view.View.dispatchTouchEvent(View.java:5553)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2027)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2027)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1762)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1953)
at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1397)
at android.app.Activity.dispatchTouchEvent(Activity.java:2431)
at dalvik.system.NativeStart.main(Native Method)

1,錯誤分析:

從錯誤信息我們也可以明白其原因,此問題根本原因就是由於將要彈出的dialog所要依附的View已經不存在導致的。

2,什麽地方可能照成此問題:當界面銷毀後再彈出來;或者界面跳轉時我們的view發生改變,dialog依附的context發生變化或者界面未運行了。

此外,很多時候我們需要通過一個非組件類來調用一個view類的方法來彈出dialog或Toast,這樣就需要再提供一個靜態context來創建這個dialog或者Toast

例如我們在一個view中通過一個靜態類來彈出一個對話框:

AlertDialog.Builder builder = new AlertDialog.Builder(mContextNew);

當然並不是所有靜態context都是可以用來創建dialog的,例如***App().getApplication().getApplicationContext()這個context就不行,因為它並不代表哪一個Activity或者View。。這樣就無法add這個dialog。

此view用於綁定顯示數據,我們在其構造方法中初始化一個靜態變量mContextNew為此view的mContext。這樣我們就可以通過一個靜態類來彈出對話框了,只需傳入這個靜態的context(mContextNew)就可以了。。

但是這個靜態的context如果只在構造方法中初始化的話是會存在問題的,因為如果另起了一個界面其綁定數據的view也是用的這個view那麽這個靜態context就會被重新修改。。

因此當這個新的界面finish後返回到上次的界面,這個靜態的context是剛才已經finish的view的context。因此如果仍然傳入這個靜態變量通過一個靜態類來彈出對話框就會出現上述找不到window的錯誤了。

解決辦法:

對於tab頁出現的錯誤可以用其父類的context來彈出dialog; 對於界面已經銷毀引起的錯誤就只能判斷界面是否存在然後再彈出了;

對於利用靜態context來彈出的dialog可以通過規避的方式來解決,比如避免出現靜態context被修改。。但是這樣就可能限制了我們程序的功能。。

因此我們可以通過在bind數據時時時更新這個靜態context就可以解決此問題了,這樣就可以保證這個靜態的context在任何view中都是當前的界面的view的context。就不會出現找不到其父類window了。

===== 3 android.view.WindowManager $ BadTokenException:無法添加窗口 - 令牌null是無效的; 為您的活動運行?

  1. 這裏主要說的是你的android裏一個Activity發生窗體泄漏了,也就是我們常說的內存泄漏,為什麽窗體會泄漏,

    主要是你的打開一個PopupWindow(窗體)時,如圖。它沒有關閉PopupWindow(窗體),就退出這個Activity,就會發生這個錯誤,

    因為這裏就有一個順序,你要先關閉PopupWindow,再關閉Activity,這個一定的,PopupWindow(窗體)不能獨立存在。

  2. 明白這個,你就容易解決了,你先用(dismiss)關閉就行,在你的窗體需要關閉時,加上這句:

    (PopupWindow.dismiss;)PopupWindow這個是你項目裏你窗體的名字。最好做一個判斷,判斷窗體是否為空,如果不為空就關閉,不然有時空也關閉也會出錯。

========= 2 Button上點擊一下彈出一個對話框,結果遇到一個問題,android.view.WindowManager$BadTokenException: Unable to add window報了這個錯。

private void showCustomDialog() {
AlertDialog.Builder builder;
AlertDialog dialog;
LayoutInflater inflator = (LayoutInflater) LayoutInflatorActivity.this.getSystemService(LAYOUT_INFLATER_SERVICE);
View view = inflator.inflate(R.layout.dialoglayout, null);
TextView text = (TextView) view.findViewById(R.id.textview);
ImageButton imageButton = (ImageButton) view.findViewById(R.id.imageButton);
builder = new AlertDialog.Builder(this);
builder.setView(view);
dialog = builder.create();
dialog.show();
}

在這句上報錯了。因為本來我的寫法是:builder = new AlertDialog.Builder(this.getApplicationContext());

因為看了API 是new AlertDialog.Builder(Context context);想著也沒什麽語法錯誤吧。結果網上搜了一下,獲取上下文this.getApplicationContext()); 和 this的區別:

這裏的this指的當然就是Acitivity.this , 指的是這個Acitivity的上下文,而this.getApplicationContext()指的則是整個應用的上下文。

對於AlertDialog來說,是需要依賴一個View,而View是對應於Activity的。

那麽為什麽會報錯呢,這裏涉及到一個生命周期的問題了。

對於一個應用Context來說,它的生命周期是整個應用程序的生命周期,而對於Activity來說,當它銷毀之後它的生命周期就結束了。


AlertDialog是屬於Acitivity的,當Activity銷毀的時候它也必須銷毀, 所以這裏我們指定是Activity的Context。

==========1 android.view.WindowManager$BadTokenException: Unable to add window

android.view.WindowManager$BadTokenException: Unable to add window -- token android.app.LocalActivityManager$LocalActivityRecord@45f48c40 is not valid; is your activity running? 今天在寫android 的google 地圖時遇到一個問題,我在地圖上添加一個Overlay 然後想在點擊這個overlay 圖標的時候彈對話框Dialog, 按這樣的思路寫完後,測試報出了上面的異常。 代碼如下: //這是一個繼承了ItemizedOverlay 的類中的方法。 @Override public boolean onTap(int i) { // TODO Auto-generated method stub OverlayItem item = allMapOverlays.get(i); AlertDialog.Builder dialog = new AlertDialog.Builder(context); dialog.setTitle(item.getTitle()); dialog.setMessage(item.getSnippet()); dialog.show(); return true; } 查資料說問題在於 context. 說不能使用 getApplicationContext(),this 所得到的Context 必須用your_Activity.this 所獲取的Context. 而我就是用最後一種的,還是出差。 於是我想下我的實際的運行環境,我的地圖是在tabActivity 中的,那麽得到當前的窗體管理者應該是上一級TabActivity 所有,而非我的地圖Activity 於是我 用 getParent()所得到的Context,運行成功。 原因:錯誤在PopupWindow.showAtLocation(findViewById(R.id.main), Gravity.BOTTOM,0,0); popwindow必須依附於某一個view,而在oncreate中view還沒有加載完畢,必須要等activity的生命周期函數全部執行完畢,你需要依附的view加載好後才可以執行popwindow。

解決辦法1:showAtLocation()函數可以這樣改:

//修正後代碼
[java] view plain copy
  1. findviewById(R.id.mView).post(new Runnable() {
  2. @Override
  3. public void run() {
  4. popwindow.showAtLocation(mView, Gravity.CENTER, 0, 0);
  5. }
  6. });

總結: PopupWindow必須在某個事件中顯示或者是開啟一個新線程去調用,不能直接在onCreate方法中顯示一個Popupwindow,否則永遠會有以上的錯誤。

bug_ _ android.view.WindowManager$BadTokenException: Unable to add window -- token