Проблемы с созданием всплывающего 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);
Во-вторых, я сделал то же самое с этим кодом:
- Как использовать поставщика контента SMS? Где документы?
- Как использовать устаревший HTTP-клиент Apache на Android Marshmallow?
- Низкое качество изображения / изображения при захвате с камеры
- При проверке флажка в listview также проверяются другие случайные флажки
- Как получить количество непрочитанных писем Gmail (на Android)
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 – недействительно»
Что в мире я делаю неправильно? Я очень новичок, поэтому, пожалуйста, несите меня.
- Как стиль PopupMenu?
- Android Studio 3.0 Выполнение не выполнено для задачи: невозможно объединить dex
- Android mock location на устройстве?
- Ошибка ADB с установкой INSTALL_FAILED_TEST_ONLY
- Как использовать перехватчик для добавления заголовков в «Дооснащение 2.0»
- Запись PCM записанных данных в WAV-файл (java android)
- Как открыть проект Android Studio в Eclipse?
- Почему добавление OnClickListener внутри onBindViewHolder из RecyclerView.Adapter считается плохой практикой?
Чтобы избежать 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 …