Android 1.6: "android.view.WindowManager$BadTokenException: невозможно добавить окно - нулевой токен не для приложения"

Я пытаюсь открыть диалоговое окно, но каждый раз, когда я пытаюсь открыть его, оно выдает это исключение:

Uncaught handler: thread main exiting due to uncaught exception
android.view.WindowManager$BadTokenException: 
     Unable to add window -- token null is not for an application
  at android.view.ViewRoot.setView(ViewRoot.java:460)
  at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)
  at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
  at android.app.Dialog.show(Dialog.java:238)
  at android.app.Activity.showDialog(Activity.java:2413)

Я создаю это, звоня showDialog с идентификатором дисплея. onCreateDialog обработчик логирует нормально, и я могу пройти по нему без проблем, но я прикрепил его, так как кажется, что я что-то упустил:

@Override
public Dialog onCreateDialog(int id)
{
    Dialog dialog;
    Context appContext = this.getApplicationContext();
    switch(id)
    {
        case RENAME_DIALOG_ID:
            Log.i("Edit", "Creating rename dialog...");
            dialog = new Dialog(appContext);
            dialog.setContentView(R.layout.rename);
            dialog.setTitle("Rename " + noteName);
            break;
        default:
            dialog = null;
            break;
    }
    return dialog;      
}

Чего-то не хватает в этом? Некоторые вопросы говорили о наличии этой проблемы при создании диалога из onCreateЭто происходит потому, что действие еще не создано, но это происходит из-за вызова объекта меню, и appContext Кажется, переменная правильно заполнена в отладчике.

16 ответов

Решение

Вместо:Context appContext = this.getApplicationContext();Вы должны использовать указатель на активность, в которой вы находитесь (вероятно, this).

Сегодня меня это тоже укусило, надоедливая часть getApplicationContext() дословно от developer.android.com:(

Вы не можете отобразить окно / диалог приложения через Контекст, который не является Деятельностью. Попробуйте передать действительную ссылку на активность

То же самое относится и к getApplicationContext.

Документы на сайте Android говорят, что использовать его, но он не работает...grrrrr:-P

Просто делать:

dialog = new Dialog(this); 

"this" - это обычно ваша активность, с которой вы запускаете диалог.

Документы Android предлагают использовать getApplicationContext();

но он не будет работать вместо того, чтобы использовать текущую активность при создании экземпляра AlertDialog.Builder или AlertDialog или Dialog...

Пример:

AlertDialog.Builder builder = new  AlertDialog.Builder(this);

или же

AlertDialog.Builder builder = new  AlertDialog.Builder((Your Activity).this);

Вместо getApplicationContext()Просто используйте ActivityName.this

У меня была похожая проблема, где у меня был другой класс, примерно такой:

public class Something {
  MyActivity myActivity;

  public Something(MyActivity myActivity) {
    this.myActivity=myActivity;
  }

  public void someMethod() {
   .
   .
   AlertDialog.Builder builder = new AlertDialog.Builder(myActivity);
   .
   AlertDialog alert = builder.create();
   alert.show();
  }
}

Большую часть времени работал нормально, но иногда он вылетал с той же ошибкой. Тогда я понимаю, что в MyActivity Я имел...

public class MyActivity extends Activity {
  public static Something something;

  public void someMethod() {
    if (something==null) {
      something=new Something(this);
    }
  }
}

Потому что я держал объект как staticвторой прогон кода все еще содержал исходную версию объекта и, таким образом, все еще ссылался на оригинальную Activity, которого давно не было.

Глупая глупая ошибка, тем более что мне не нужно было держать объект как static на первом месте...

Просто измените это на

AlertDialog.Builder alert_Categoryitem = 
    new AlertDialog.Builder(YourActivity.this);

Вместо

AlertDialog.Builder alert_Categoryitem = 
    new AlertDialog.Builder(getApplicationContext());

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

dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

Это требует SYSTEM_ALERT_WINDOW разрешение:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

Как говорят в документах:

Очень немногие приложения должны использовать это разрешение; Эти окна предназначены для взаимодействия на уровне системы с пользователем.

Это решение, которое вы должны использовать, только если вам требуется диалоговое окно, которое не привязано к действию.

Не использовать getApplicationContext() при объявлении диаложа

Всегда используйте this или ваш activity.this

Это сработало для меня

new AlertDialog.Builder(MainActivity.this)
        .setMessage(Html.fromHtml("<b><i><u>Spread Knowledge Unto The Last</u></i></b>"))
        .setCancelable(false)
        .setPositiveButton("Dismiss",
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                    }
                }).show();

использование

ActivityName.this

Для вложенных диалогов эта проблема очень распространена, она работает, когда

AlertDialog.Builder mDialogBuilder = new AlertDialog.Builder(MyActivity.this);

используется вместо

mDialogBuilder = new AlertDialog.Builder(getApplicationContext);

эта альтернатива.

Вы также можете сделать это

public class Example extends Activity {
    final Context context = this;
    final Dialog dialog = new Dialog(context);
}

Это сработало для меня!

Как уже говорилось, вам нужен Activity в качестве контекста для диалога, используйте "YourActivity.this" для статического контекста или проверьте здесь, как использовать динамический контекст в безопасном режиме.

Лучший и самый безопасный способ показать "ProgressDialog" в AsyncTask, избегая проблемы утечки памяти, - это использовать "Обработчик" с Looper.main().

    private ProgressDialog tProgressDialog;

тогда в 'onCreate'

    tProgressDialog = new ProgressDialog(this);
    tProgressDialog.setMessage(getString(R.string.loading));
    tProgressDialog.setIndeterminate(true);

Теперь вы закончили с установочной частью. Теперь вызовите showProgress() и hideProgress() в AsyncTask.

    private void showProgress(){
        new Handler(Looper.getMainLooper()){
            @Override
            public void handleMessage(Message msg) {
                tProgressDialog.show();
            }
        }.sendEmptyMessage(1);
    }

    private void hideProgress(){
        new Handler(Looper.getMainLooper()){
            @Override
            public void handleMessage(Message msg) {
                tProgressDialog.dismiss();
            }
        }.sendEmptyMessage(1);
    }
public class Splash extends Activity {

    Location location;
    LocationManager locationManager;
    LocationListener locationlistener;
    ImageView image_view;
    ublic static ProgressDialog progressdialog;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.splash);
        progressdialog = new ProgressDialog(Splash.this);
           image_view.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub

                        locationManager.requestLocationUpdates("gps", 100000, 1, locationlistener);
                        Toast.makeText(getApplicationContext(), "Getting Location plz wait...", Toast.LENGTH_SHORT).show();

                            progressdialog.setMessage("getting Location");
                            progressdialog.show();
                            Intent intent = new Intent(Splash.this,Show_LatLng.class);
//                          }
        });
    }

Текст здесь:-
использовать это для получения activity контекст для progressdialog

 progressdialog = new ProgressDialog(Splash.this);

или же progressdialog = new ProgressDialog(this);

использовать это для получения контекста приложения для BroadcastListener не для progressdialog,

progressdialog = new ProgressDialog(getApplicationContext());
progressdialog = new ProgressDialog(getBaseContext());

Попробуй сбросить dialog тип окна для

WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

Не забудьте использовать разрешение android.permission.SYSTEM_ALERT_WINDOW

Другие вопросы по тегам