Отображать AlertDialog как окно оверлея системы из службы
У меня проблема с отображением AlertDialog из Service. Я могу показать окно пользовательского макета с помощью Toast или с помощью WindowManager (TYPE_SYSTEM_ALERT или TYPE_SYSTEM_OVERLAY). Но я не хочу использовать пользовательский макет, я предпочитаю использовать красивый графический интерфейс AlertDialog напрямую.
Сценарий:
- Запуск службы. Активная активность отсутствует.
- В случае какого-либо внешнего события служба отправляет уведомление
- Когда пользователь нажимает "Уведомление", служба информируется через PendingIntent, и AlertDialog должен отображаться (создается с помощью
AlertDialog.Builder(this)
)
Ошибка:
ERROR/AndroidRuntime(1063): Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
Поиск ответа приводит к тому, что я пытаюсь сделать то, что в настоящее время невозможно (Android 2.2). Или может быть.
Ответы
Ответ 1
найдено решение, соответствующее описанному сценарию.
-
Новая активность была создана и запущена с сервиса. Однако это активность с полупрозрачным фоном. Такая операция не имеет строки super.setContentView()
в onCreate()
. Более важно, чтобы обеспечить прозрачность.
@android: стиль /Theme.Translucent
вводится в теге Тема для этого действия в графическом интерфейсе AndroidManifest.xml. Итак, новая строка, добавленная в манифест xml,
android:theme="@android:style/Theme.Translucent"
-
В onCreate()
происходит фактическое отображение AlertDialog
-
Нажатие на кнопки AlertDialog приводит к закрытию и отправке диалога и активности Intent (или использованию некоторых других средств) для доставки результата в Сервис.
-
Убедитесь, что вы определили setOnDismissListener() для диалогового окна (реализация должна вызвать функцию finish() для активности). Если вы этого не сделаете, нажмите клавишу "Назад", чтобы отменить диалог, но оставит вас в текущей активности, которая прозрачна и выглядит для пользователя, как будто что-то действительно не так.
Ответ 2
Спасибо за ваше решение.
Я столкнулся с той же проблемой и разработал с вашей помощью.
Я поставил этот ответ, чтобы поделиться своим путем, чтобы передать результат обратно в службу.
Я не создавал дополнительный пользовательский класс намерений и не решал проблему прохождения результатов только с помощью методов Intent.putExtra()
с некоторыми трюками.
В этой службе используйте этот код, чтобы запустить DialogActivity
, который отображает диалоговое окно предупреждения в onCreate()
.
Intent intent = new Intent(this.getApplicationContext(), DialogActivity.class);
intent.putExtra(DialogActivity.CLASS_KEY, this.getClass().getCanonicalName());
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
И в DialogActivity
, закончите так:
private void returnOk(boolean ok) {
Intent srcIntent = this.getIntent();
Intent tgtIntent = new Intent();
String className = srcIntent.getExtras().getString(CLASS_KEY);
Log.d("DialogActivity", "Service Class Name: " + className);
ComponentName cn = new ComponentName(this.getApplicationContext(), className);
tgtIntent.setComponent(cn);
tgtIntent.putExtra(RESULT_KEY, ok ? RESULT_OK : RESULT_CANCEL);
this.startService(tgtIntent);
this.finish();
}
Наконец, в службе переопределите метод onStartCommand()
и получите результат от намерения.
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
int ret = super.onStartCommand(intent, flags, startId);
Bundle extras = intent.getExtras();
if (extras != null) {
int result = extras.getInt(DialogActivity.RESULT_KEY, -1);
if (result >= 0) {
if (result == DialogActivity.RESULT_OK) {
// Your logic here...
}
} else {
// Your other start logic here...
}
}
return ret;
}
Я не уверен, является ли этот способ хорошим решением, по крайней мере, он работает для меня. Надеюсь, это будет полезно для кого-то вроде меня.
Полный источник можно найти здесь: