Проблемы с созданием всплывающего 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

Interesting Posts

Обработка ошибок в вызовах getJSON

Почему сервер передач-job-server не принимает соединения при работе в качестве службы?

Как добавить новый источник в Gradle?

Остановка CHKDSK

Как включить Samsung EVO 840 mSATA SSD Self-Encrypting Drive с Intel RST RAID 0

jQuery ajax и SSL?

Как аутентифицировать пользователя только с учетной записью Google в действиях в Google?

Инструменты анализа профилировщика и памяти для Delphi

ViewModels в MVC / MVVM / Seperation of layers – лучшие практики?

Есть ли способ указать class реализации Doctrine2 Entitymanager в Symfony2?

Могу ли я использовать радиатор LGA 1156/1155 на материнской плате LGA 1150?

cygwin устанавливает разрешение файла на 000

Как запустить программу с повышенными разрешениями с учетной записи пользователя с ограниченным доступом без пароля администратора?

AVAudioPlayer: как изменить скорость воспроизведения аудио?

Chromebook: как увеличить размер графического интерфейса веб-браузера Chrome?

Давайте будем гением компьютера.