Проблемы с созданием всплывающего окна в Android Activity
Я пытаюсь создать всплывающее окно, которое появляется только при первом запуске приложения. Я хочу, чтобы он отображал текст и имел кнопку для закрытия всплывающего окна. Однако у меня возникли проблемы с тем, чтобы заставить всплывающее окно работать. Я пробовал два разных способа сделать это:
сначала у меня есть XML-файл, который объявляет макет всплывающего окна popup.xml (textview внутри linearlayout), и я добавил Это в OnCreate () моего основного Активность:
PopupWindow pw = new PopupWindow(findViewById(R.id.popup), 100, 100, true);
pw.showAtLocation(findViewById(R.id.main), Gravity.CENTER, 0, 0);
во-вторых, я сделал то же самое с этим кодом:
final LayoutInflater inflater = (LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
PopupWindow pw = new PopupWindow(inflater.inflate(R.layout.popup, (ViewGroup) findViewById(R.layout.main) ), 100, 100, true);
pw.showAtLocation(findViewById(R.id.main_page_layout), Gravity.CENTER, 0, 0);
первый бросает исключение NullPointerException, а второй бросает исключение BadTokenException и говорит: "невозможно добавить окно-токен null недопустим"
что я делаю не так? Я очень новичок, поэтому, пожалуйста, медведь со мной.
13 ответов
чтобы избежать BadTokenException, вам нужно отложить отображение всплывающего окна до тех пор, пока не будут вызваны все методы жизненного цикла (-> отображается окно активности):
findViewById(R.id.main_page_layout).post(new Runnable() {
public void run() {
pw.showAtLocation(findViewById(R.id.main_page_layout), Gravity.CENTER, 0, 0);
}
});
решение, предоставленное Kordzik, не будет работать, если вы запустите 2 действия последовательно:
startActivity(ActivityWithPopup.class);
startActivity(ActivityThatShouldBeAboveTheActivivtyWithPopup.class);
Если вы добавите всплывающее окно таким образом в таком случае, вы получите тот же сбой, потому что ActivityWithPopup не будет прикреплен к окну в этом случае.
более универсальным решением является onAttachedToWindow и onDetachedFromWindow.
а также нет необходимости в postDelayed (Runnable, 100). Потому что это 100 Миллис не гарантирует ничего
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
Log.d(TAG, "onAttachedToWindow");
showPopup();
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
Log.d(TAG, "onDetachedFromWindow");
popup.dismiss();
}
Я обнаружил, что принятый ответ не работает для меня. Я все еще получил ошибку bad token.. Поэтому я просто вызвал runnable из обработчика с задержкой как таковой..
new Handler().postDelayed(new Runnable() {
public void run() {
showPopup();
}
}, 100);
есть два сценария, когда это исключение может произойти. Один упоминается kordzik. Другой сценарий упоминается здесь: http://blackriver.to/2012/08/android-annoying-exception-unable-to-add-window-is-your-activity-running/
убедитесь, что вы справитесь с ними обоими
решение состоит в том, чтобы установить режим spinner в диалоговое окно, как показано ниже:
android:spinnerMode="dialog"
или
Spinner(Context context, int mode)
tnxs RamallahDroid
в зависимости от варианта использования для типов всплывающих окон для отображения сообщения Установите тип всплывающего окна в TYPE_TOAST с помощью setWindowLayoutType()
избегает проблемы, так как этот тип всплывающего окна не зависит от базовой активности.
Edit: один из побочных эффектов: нет взаимодействия во всплывающем окне для API http://www.jianshu.com/p/634cd056b90c )
в конечном итоге я использую TYPE_PHONE (как приложение имеет разрешение SYSTEM_ALERT_WINDOW, иначе это тоже не сработает).
вы можете проверить rootview, если у него есть токен. Вы можете получить Родительский макет, определенный из вашего действия xml, mRootView
if (mRootView != null && mRootView.getWindowToken() != null) {
popupWindow.showAtLocation();
}
проверяем, что findViewById
возвращает что - то-вы можете вызвать его слишком рано, прежде чем макет будет построен
также вы можете опубликовать вывод logcat для исключений, которые вы получаете
вы также можете попробовать использовать эту проверку:
public void showPopupProgress (){
new Handler().post(new Runnable() {
@Override
public void run() {
if (getWindow().getDecorView().getWindowVisibility() == View.GONE) {
showPopupProgress();
return;
}
popup.showAtLocation(.....);
}
});
}
Если вы показываете всплывающее окно в другом всплывающем окне, не используйте представление в первом POP, используйте родительское представление origin.
pop.showAtLocation(parentView, ... );
у меня была та же проблема (BadTokenException) с AlertDialog на dialog.show()
. Я делал AlertDialog, следуя некоторому примеру. В моем случае причиной этой проблемы была строка
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_TOAST)
все стало работать после того, как я удалил его.