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