Проблемы с созданием всплывающего окна в Android Activity - PullRequest
52 голосов
/ 15 ноября 2010

Я пытаюсь создать всплывающее окно, которое появляется только при первом запуске приложения.Я хочу, чтобы он отображал некоторый текст и имел кнопку, чтобы закрыть всплывающее окно.Однако у меня проблемы с тем, чтобы заставить PopupWindow работать даже.Я попробовал два разных способа сделать это:

Во-первых, у меня есть файл XML, который объявляет макет всплывающего окна с именем popup.xml (текстовое представление внутри линейного слоя), и я добавил это в 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 и говорит «Unableдобавить окно - токен null недействителен "

Что в мире я делаю неправильно?Я очень новичок, поэтому, пожалуйста, потерпите меня.

Ответы [ 13 ]

175 голосов
/ 17 января 2011

Чтобы избежать 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);
   }
});
28 голосов
/ 19 ноября 2015

Решение, предоставленное Kordzik, не будет работать, если вы запустите 2 действия подряд:

startActivity(ActivityWithPopup.class);
startActivity(ActivityThatShouldBeAboveTheActivivtyWithPopup.class);

Если вы добавите всплывающее окно таким образом в подобном случае, вы получите тот же сбой, потому что ActivityWithPopup не будет присоединен к Window в этом случае.

Более универсальное решение: 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();
}
17 голосов
/ 03 июля 2013

Принятый ответ не работает для меня.Я все еще получил BadTokenException.Поэтому я просто вызвал Runnable из обработчика с задержкой как таковой:

new Handler().postDelayed(new Runnable() {
    public void run() {
        showPopup();
    }
}, 100);
7 голосов
/ 08 января 2018

используйте класс Context, например.MainActivity.this вместо getApplicationContext ()

4 голосов
/ 21 июля 2013

решение состоит в том, чтобы установить режим вращения в диалоговое окно, как показано ниже:

android:spinnerMode="dialog"

или

Spinner(Context context, int mode)
tnxs RamallahDroid

См. Это.

4 голосов
/ 26 июня 2013

Существует два сценария, когда может возникнуть это исключение. Один упоминается Кордзик. Другой сценарий упоминается здесь: http://blackriver.to/2012/08/android-annoying-exception-unable-to-add-window-is-your-activity-running/

Убедитесь, что вы справляетесь с ними обоими

1 голос
/ 17 августа 2016

Вы можете проверить root-вид, если у него есть токен.Вы можете получить родительский макет, определенный из вашей активности xml, mRootView

if (mRootView != null && mRootView.getWindowToken() != null) {
    popupWindow.showAtLocation();
}
1 голос
/ 14 декабря 2015

В зависимости от варианта использования, для типов всплывающих окон, отображающих сообщение, установка типа всплывающего окна на TYPE_TOAST с использованием setWindowLayoutType() позволяет избежать этой проблемы, поскольку этот тип всплывающих окон не зависит от основного действия.

Редактировать: один из побочных эффектов: нет взаимодействия во всплывающем окне для API <= 18, поскольку сенсорные / фокусируемые события будут удалены системой.(<a href="http://www.jianshu.com/p/634cd056b90c" rel="nofollow">http://www.jianshu.com/p/634cd056b90c)

В итоге я использую TYPE_PHONE (поскольку у приложения есть разрешение SYSTEM_ALERT_WINDOW, в противном случае это тоже не будет работать).

0 голосов
/ 08 июня 2018

У меня была такая же проблема (BadTokenException) с AlertDialog на dialog.show(). Я делал AlertDialog, следуя некоторому примеру. В моем случае причиной этой проблемы была строка dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_TOAST)

Все стало работать после того, как я его удалил.

0 голосов
/ 01 сентября 2016

Если вы показываете PopupWindow в другом PopupWindow, не используйте представление в первом POP, используйте родительское представление источника.

pop.showAtLocation(parentView, ... );
...