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();
    }

猜你喜欢

转载自blog.csdn.net/sdsxtianshi/article/details/78530491