首页 > 代码库 > PopupWindow嵌套PopupWindow时报Unable to add window的处理

PopupWindow嵌套PopupWindow时报Unable to add window的处理

    今天在帮同学实现一个PopupWindow嵌套PopupWindow时报了异常,导致第二个POP不能显示:

android.view.WindowManager$BadTokenException: Unable to add window -- token android.view.ViewRootImpl$W@4340e618 is not valid; is your activity running?

先贴代码:

volleytest_lay.xml,pop_first_lay.xml,pop_second_lay:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:background="#ffffff"

    android:orientation="vertical" >


    <Button

        android:id="@+id/popBtn"

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:text="弹出POP菜单" />


</LinearLayout>

PopupWindowActivity.java :

public class PopupWindowActivity extends Activity {

private Button popBtn = null, mButton;

private Context mContext;

private PopupWindow mSecondPOPWindow, mFirstPOPWindow = null;


@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.volleytest_lay);

mContext = this;

popBtn = (Button) findViewById(R.id.popBtn);


initPopFirst();


initListener();

}


private void initListener() {

// TODO Auto-generated method stub

popBtn.setOnClickListener(new OnClickListener() {


@Override

public void onClick(View v) {

// TODO Auto-generated method stub

if (mFirstPOPWindow.isShowing()) {

// 隐藏窗口,如果设置了点击窗口外小时即不需要此方式隐藏

mFirstPOPWindow.dismiss();

} else {

// 显示窗口

mFirstPOPWindow.showAsDropDown(v);

}

}


});

}

/**

* 初始化第一个POP

*/

private void initPopFirst() {

View firstView = getLayoutInflater().inflate(R.layout.pop_first_lay,

null);

mFirstPOPWindow = new PopupWindow(firstView, LayoutParams.MATCH_PARENT,

LayoutParams.MATCH_PARENT, true);

mFirstPOPWindow.setTouchable(true);

mFirstPOPWindow.setOutsideTouchable(true);

mFirstPOPWindow.setFocusable(true);

mFirstPOPWindow.setBackgroundDrawable(new BitmapDrawable());

initPopSecond();

Button btn = (Button) firstView.findViewById(R.id.popFirstBtn);

btn.setOnClickListener(new OnClickListener() {


@Override

public void onClick(View v) {

try {

if (mSecondPOPWindow.isShowing()) {

// 隐藏窗口,如果设置了点击窗口外小时即不需要此方式隐藏

mSecondPOPWindow.dismiss();

} else {

// 显示窗口

mSecondPOPWindow.showAsDropDown(v, 500, 500);

}

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

/*//测试AlertDialog

new AlertDialog.Builder(mContext)

.setTitle("确认")

.setMessage("确定吗?")

.setPositiveButton("是", null)

.setNegativeButton("否", null)

.show();*/


}

});

}

/**

* 初始化第二个POP

*/

private void initPopSecond() {

View popSecView = PopupWindowActivity.this.getLayoutInflater().inflate(

R.layout.pop_second_lay, null);

mSecondPOPWindow = new PopupWindow(popSecView,

LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, true);

mSecondPOPWindow.setTouchable(true);

mSecondPOPWindow.setOutsideTouchable(true);

mSecondPOPWindow.setFocusable(true);

mSecondPOPWindow.setBackgroundDrawable(new BitmapDrawable());

Button popSecondBtn = (Button) popSecView

.findViewById(R.id.popSecondBtn);

popSecondBtn.setOnClickListener(new OnClickListener() {


@Override

public void onClick(View v) {

// TODO Auto-generated method stub

Toast.makeText(PopupWindowActivity.this, "第二个POP", 100).show();

}

});

}

}

此时是报异常的,经过不断的排查和网上搜查,问题依然没有解决。比如这里http://stackoverflow.com/questions/8782250/popupwindow-badtokenexception-unable-to-add-window-token-null-is-not-valid 只是提出讨论并么有实际解决出来。

异常的原因是因为第一个PopupWindow已经显示后,他就控制了整个Window的焦点,此时第一个POP则成为了父Window,而PopupWindow是不能以子window的形式展现的,他们必须都要以父Window显示,所以第二个POP无法添加上去。

修改后:

public class PopupWindowActivity extends Activity {

private Button popBtn = null, mButton;

private Context mContext;

private PopupWindow mSecondPOPWindow, mFirstPOPWindow = null;

private View parientView;


@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.volleytest_lay);

mContext = this;

popBtn = (Button) findViewById(R.id.popBtn);


initPopFirst();


initListener();

}


private void initListener() {

// TODO Auto-generated method stub

popBtn.setOnClickListener(new OnClickListener() {


@Override

public void onClick(View v) {

// TODO Auto-generated method stub

if (mFirstPOPWindow.isShowing()) {

// 隐藏窗口,如果设置了点击窗口外小时即不需要此方式隐藏

mFirstPOPWindow.dismiss();

} else {

// 显示窗口

mFirstPOPWindow.showAsDropDown(v);

}

// 给第二个POP显示时用,解决了嵌套时出现的Unable to add window的问题

parientView = v;

}


});

}

/**

* 初始化第一个POP

*/

private void initPopFirst() {

View firstView = getLayoutInflater().inflate(R.layout.pop_first_lay,

null);

mFirstPOPWindow = new PopupWindow(firstView, LayoutParams.MATCH_PARENT,

LayoutParams.MATCH_PARENT, true);

mFirstPOPWindow.setTouchable(true);

mFirstPOPWindow.setOutsideTouchable(true);

mFirstPOPWindow.setFocusable(true);

mFirstPOPWindow.setBackgroundDrawable(new BitmapDrawable());

initPopSecond();

Button btn = (Button) firstView.findViewById(R.id.popFirstBtn);

btn.setOnClickListener(new OnClickListener() {


@Override

public void onClick(View v) {

try {

if (mSecondPOPWindow.isShowing()) {

// 隐藏窗口,如果设置了点击窗口外小时即不需要此方式隐藏

mSecondPOPWindow.dismiss();

} else {

// 显示窗口

mSecondPOPWindow.showAsDropDown(parientView, 500, 500);

}

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

/*//测试AlertDialog

new AlertDialog.Builder(mContext)

.setTitle("确认")

.setMessage("确定吗?")

.setPositiveButton("是", null)

.setNegativeButton("否", null)

.show();*/


}

});

}

/**

* 初始化第二个POP

*/

private void initPopSecond() {

View popSecView = PopupWindowActivity.this.getLayoutInflater().inflate(

R.layout.pop_second_lay, null);

mSecondPOPWindow = new PopupWindow(popSecView,

LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, true);

mSecondPOPWindow.setTouchable(true);

mSecondPOPWindow.setOutsideTouchable(true);

mSecondPOPWindow.setFocusable(true);

mSecondPOPWindow.setBackgroundDrawable(new BitmapDrawable());

Button popSecondBtn = (Button) popSecView

.findViewById(R.id.popSecondBtn);

popSecondBtn.setOnClickListener(new OnClickListener() {


@Override

public void onClick(View v) {

// TODO Auto-generated method stub

Toast.makeText(PopupWindowActivity.this, "第二个POP", 100).show();

}

});

}

}

    解决方式请看红色标出的部分,而且解决的方式相当简单(此方案得益于一个同学),有时候我们把问题想得太复杂了,反而会使我们陷入一定的僵局,换一种思路去看待问题,必然会柳暗花明。

    其实这个问题可以换一种方式解决,那就是第二个POP用AlertDialog显示也是可以,看代码中我注释点的几句就会明白,只是你非要用POP时就用我提供的这个就可以了,当然还有可能有更多的解决方案,如果有其他解决方案时,请分享一起学习,写此博文,只是希望对目前还没解决的人提供一点帮助。


源码下载



PopupWindow嵌套PopupWindow时报Unable to add window的处理