此文包含android.view.WindowManager$BadTokenException的4種情形:
1.Unable to add window --token null is not valid; is your activity running
**2.Unable to add window --token null is not for an application **
3.Unable to add window -- token android.os.BinderProxy@XXX is not valid;
is your activity running**4.Unable to add window -- token android.app.LocalActivityManager
$LocalActivityRecord @xxx is not valid; is your activity running
**
情形1.android.view.WindowManager$BadTokenException: Unable to add window --token null is not valid; is your activity running?異常處理。
$BadTokenException: Unable to add window --
token null is not valid; is your activity running
E/AndroidRuntime(1412): at android.view.ViewRootImpl.setView(ViewRootImpl.java:538)
......
該異常多見于Popup Window組件的使用中拋出烹吵。
原因:錯(cuò)誤在PopupWindow.showAtLocation(findViewById(R.id.main), Gravity.BOTTOM,0,0); popwindow必須依附于某一個(gè)view打颤,而在oncreate中view還沒有加載完畢,必須要等activity的生命周期函數(shù)全部執(zhí)行完畢于个,你需要依附的view加載好后才可以執(zhí)行popwindow氛魁。
解決辦法:showAtLocation()函數(shù)可以這樣改:
//修正后代碼
findviewById(R.id.mView).post(new Runnable() {
@Override
public void run() {
popwindow.showAtLocation(mView, Gravity.CENTER, 0, 0);
}
});
總結(jié): PopupWindow必須在某個(gè)事件中顯示或者是開啟一個(gè)新線程去調(diào)用,不能直接在onCreate方法中顯示一個(gè)Popupwindow,否則永遠(yuǎn)會(huì)有以上的錯(cuò)誤秀存。
參考:
http://stackoverflow.com/questions/4187673/problems-creating-a-popup-window-in-android-activity
情形2.android.view.WindowManager$BadTokenException: Unable to add window --token null is not for an application ?異常處理捶码。
$BadTokenException: Unable to add window --
token null is not for an application
E/AndroidRuntime(1412): at android.view.ViewRootImpl.setView(ViewRootImpl.java:538)
......
該異常多見于AlertDialog組件的使用中拋出。
//拋異常代碼
new AlertDialog.Builder(getApplicationContext()) //不能用getApplicationContext()
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle("Warnning")
.setPositiveButton("Yes", positiveListener)
.setNegativeButton( "No", negativeListener)
.create().show();
原因:導(dǎo)致報(bào)這個(gè)錯(cuò)是在于new AlertDialog.Builder(mcontext)或链,雖然這里的參數(shù)是AlertDialog.Builder(Context context)惫恼,但我們不能使用getApplicationContext()獲得的Context,而必須使用Activity,因?yàn)橹挥幸粋€(gè)Activity才能添加一個(gè)窗體。
解決方法:將new AlertDialog.Builder(Context context)中的參數(shù)用Activity.this(Activity是你的Activity的名稱)或者getActivity()來填充就可以正確的創(chuàng)建一個(gè)Dialog了澳盐。
//修正后代碼
new AlertDialog.Builder(this) //this可以替換為MainActivity.this或getActivity()
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle("Warnning")
.setPositiveButton("Yes", positiveListener)
.setNegativeButton( "No", negativeListener)
.create().show();
參考:
http://stackoverflow.com/questions/20779377/android-custom-dialog-gives-an-error
情形3.android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@XXX is not valid; is your activity running?異常處理祈纯。
android.view.WindowManager$BadTokenException: Unable to add window --
token android.os.BinderProxy@4250d6d8 is not valid; is your activity running?
at android.view.ViewRootImpl.setView(ViewRootImpl.java:698)
......
at dalvik.system.NativeStart.main(Native Method)
原因:從錯(cuò)誤信息我們也可以明白其原因,此問題根本原因就是由于將要彈出的dialog所要依附的View已經(jīng)不存在導(dǎo)致的叼耙。當(dāng)界面銷毀后再?gòu)棾鰜硗罂换蛘呓缑嫣D(zhuǎn)時(shí)我們的view發(fā)生改變,dialog依附的context發(fā)生變化或者界面未運(yùn)行了筛婉。
解決方法:界面已經(jīng)銷毀引起的錯(cuò)誤就只能判斷界面是否存在然后再?gòu)棾隽恕?/p>
//修正后代碼
if(!isFinishing()) {
alert.show();
}
https://github.com/VKCOM/vk-android-sdk/issues/21
情形4.android.view.WindowManager
LocalActivityRecord @xxx is not valid; is your activity running? 異常處理簇爆。
android.view.WindowManager$BadTokenException: Unable to add window --
token android.app.LocalActivityManager$LocalActivityRecord@43e5b158
is not valid; is your activity running?
//異常代碼
TipDialog dialog = new TipDialog(XXX.this) ;
原因:因?yàn)閚ew對(duì)話框的時(shí)候,參數(shù)context 指定成了this爽撒,即指向當(dāng)前子Activity的context入蛆。但子Activity是動(dòng)態(tài)創(chuàng)建的,不能保證一直存在硕勿。其父Activity的context是穩(wěn)定存在的安寺,所以有下面的解決辦法。
解決方法:將context替換為getParent()即可首尼。 注意:要?jiǎng)?chuàng)建dialog對(duì)象挑庶,上下文環(huán)境必須是activity,同時(shí)若ActivityGroup中嵌套ActivityGroup,嵌套多少就該使用多少個(gè)getParent()。
//修正后代碼软能,只有最多一個(gè)parent的情形
TipDialog dialog = new TipDialog(getParent()) ;
//修正后代碼迎捺,適用于一個(gè)或多個(gè)parent的情形
Activity activity = TestActivity.this;
while (activity.getParent() != null) {
activity = activity.getParent();
}
TipDialog dialog = new TipDialog(activity) ;
參考:
http://stackoverflow.com/questions/9914195/webview-in-activity-group-crashing-on-dialogs
注:為什么要使用getParent我們可以從ActivityGroup的內(nèi)部機(jī)制來理解:
TabActivity的父類是ActivityGroup,而ActivityGroup的父類是Activity。因此從Ams的角度來看查排,ActivityGroup與普通的Activity沒有什么區(qū)別凳枝,其生命周期包括標(biāo)準(zhǔn)的start,stop,resume,destroy等,而且系統(tǒng)中只允許同時(shí)允許一個(gè)ActivityGroup.但ActivityGroup內(nèi)部有一個(gè)重要成員變量跋核,其類型為L(zhǎng)ocalActivityManager,該類的最大特點(diǎn)在于它可以訪問應(yīng)用進(jìn)程的主類岖瑰,即ActivityThread類。Ams要啟動(dòng)某個(gè)Activity或者贊同某個(gè)Activity都是通過ActivityThread類執(zhí)行的砂代,而LocalActivityManager類就意味著可以通過它來裝載不同的Activity,并控制Activity的不同的狀態(tài)蹋订。注意,這里是裝載刻伊,而不是啟動(dòng)露戒,這點(diǎn)很重要椒功。所謂的啟動(dòng),一般是指會(huì)創(chuàng)建一個(gè)進(jìn)程(如果所在的應(yīng)用經(jīng)常還不存在)運(yùn)行該Activity,而裝載僅僅是指把該Activity作為一個(gè)普通類進(jìn)行加載智什,并創(chuàng)建一個(gè)該類的對(duì)象而已动漾,而該類的任何函數(shù)都沒有被運(yùn)行。裝載Activity對(duì)象的過程對(duì)AmS來講是完全不可見的荠锭,那些嵌入的Activity僅僅貢獻(xiàn)了自己所包含的Window窗口而已旱眯。而子Activity的不同狀態(tài)是通過moveToState來處理的。
所以子Activity不是像普通的Activity一樣证九,它只是提供Window而已删豺,所以在創(chuàng)建Dialog時(shí)就應(yīng)該使用getParent獲取ActivityGroup真正的Activity,才可以加Dialog加入Activity中甫贯。