unable to add window -- token null is not valid; is your activity running 錯誤解決辦法

  在使用dialog或者popupwindow時經常會出現以下錯誤導致應用crash,即獲取的token爲空,原因是使用的控件需要綁定Activity的context,而控件生成時Activity還沒有完成加載,因此會出現以下錯誤。
這裏寫圖片描述
產生錯誤的情景一般有兩種:
1. 在Activity還沒有完成加載時,調用了popupwindow或需要綁定Activity的控件,例如在onCreate或onResume中設置了popupwindow.showAtLocation方法;
2. 在Activity destroy後調用了上述類型的控件,例如在銷燬Activity時調用了Dialog.show()。

對於第一種情況有兩種解決方法:

1. 通過handler延遲加載:

private Handler popupHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case 0:
                popupWindow.showAtLocation(rootView, Gravity.CENTER,0, 0);
                popupWindow.update();
                break;
            }
        }
    };

2. 使用onWindowFocusChanged(boolean hasFocus),個人比較推薦這種方式,該方法的含義我們可以從源碼註釋裏看到:

Called when the current {@link Window} of the activity gains or loses
     * focus.  This is the best indicator of whether this activity is visible
     * to the user. As a general rule, however, a resumed activity will have window focus...  

即該方法是Activity對用戶可見時最好的指示,並且一個resumed Activity總是有獲取到焦點,也就是說當hasFocus爲true時,Activity是肯定加載完成了的,此時再調用需要綁定Activity的控件就不會出現token is null 這種錯誤了。

/**
 * Monitoring activity has finished.If it has finished, it's focus will change and call this method.
 * @param hasFocus
 */
@Override
public void onWindowFocusChanged(boolean hasFocus) {
    if (hasFocus) {
        mPopupText.setText((mSeekBarDef.getProgress()-off+1)+"分鐘");
        View rootView = LayoutInflater.from(MainActivity.this).inflate(R.layout.activity_main,null);
        mPopupWindow.showAtLocation(rootView, Gravity.NO_GRAVITY,x,y);
    }
}

對於第二種情景的解決方法是使用Activity.isFinishing()方法,還是從源碼入手:

    /**
     * Check to see whether this activity is in the process of finishing,
     * either because you called {@link #finish} on it or someone else
     * has requested that it finished.  This is often used in
     * {@link #onPause} to determine whether the activity is simply pausing or
     * completely finishing.
     *
     * @return If the activity is finishing, returns true; else returns false.
     *
     * @see #finish
     */
    public boolean isFinishing() {
        return mFinished;
    }

那麼該方法的作用就是判斷是否是否使用了finish而使Activity處於finishing的進程之中:

if (!MainActivity.this.isFinishing()){
         alertDialog.show();
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章