Проблемы с созданием всплывающего windows в Android-активности

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

Сначала у меня есть XML-файл, который объявляет макет всплывающего windows popup.xml (текстовое представление внутри 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 и говорит: «Невозможно добавить нулевой токен windows – недействительно»

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

Чтобы избежать BadTokenException, вам нужно отложить показ всплывающего windows до тех пор, пока не будут вызваны все методы жизненного цикла (-> окно активности):

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

Я обнаружил, что принятый ответ не сработал для меня. Я все еще получил плохую ошибку токена. Так что я просто вызвал runnable из Handler с задержкой как таковой ..

 new Handler().postDelayed(new Runnable() { public void run() { showPopup(); } }, 100); 

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

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

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

 android:spinnerMode="dialog" 

или

 Spinner(Context context, int mode) tnxs RamallahDroid 

Видеть это.

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

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

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

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

 if (mRootView != null && mRootView.getWindowToken() != null) { popupWindow.showAtLocation(); } 

use class Context, например. MainActivity.this вместо getApplicationContext ()

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

Также вы можете опубликовать вывод logcat для исключений, которые вы получаете

Вы также можете попробовать эту проверку:

  public void showPopupProgress (){ new Handler().post(new Runnable() { @Override public void run() { if (getWindow().getDecorView().getWindowVisibility() == View.GONE) { showPopupProgress(); return; } popup.showAtLocation(.....); } }); } 

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

 pop.showAtLocation(parentView, ... ); 

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

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

Вы можете указать y-offset для учета строки состояния из метода pw.showAtLocation

  • Android: Как получить радиогруппу с togglebuttons?
  • Как вручную включить внешний пакет aar с помощью новой системы сборки Gradle Android
  • Как сохранить SMS в папку «Входящие» в андроиде?
  • Изменение цвета выделенного андроида
  • Пользовательский элемент строки для Android для ListView
  • Как отключить историю совместного использования при использовании ShareActionProvider?
  • Нет сгенерированного файла R.java в моем проекте
  • Получать MMS-сообщения в Android KitKat
  • Как добавить новую колонку в базу данных SQLite для Android?
  • Android Удалить запрос
  • Android: как отображать предварительный просмотр камеры с помощью обратного вызова?
  • Давайте будем гением компьютера.