Android:ProgressDialog.show() выходит из строя с getApplicationContext

StackOverflow https://stackoverflow.com/questions/1561803

  •  21-09-2019
  •  | 
  •  

Вопрос

Кажется, я не могу понять, почему это происходит.Этот код:

mProgressDialog = ProgressDialog.show(this, "", getString(R.string.loading), true);

работает просто отлично.Однако этот код:

mProgressDialog = ProgressDialog.show(getApplicationContext(), "", getString(R.string.loading), true);

выдает следующее исключение:

W/WindowManager(  569): Attempted to add window with non-application token WindowToken{438bee58 token=null}.  Aborting.
D/AndroidRuntime( 2049): Shutting down VM
W/dalvikvm( 2049): threadid=3: thread exiting with uncaught exception (group=0x4001aa28)
E/AndroidRuntime( 2049): Uncaught handler: thread main exiting due to uncaught exception
E/AndroidRuntime( 2049): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.tastekid.TasteKid/com.tastekid.TasteKid.YouTube}: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
E/AndroidRuntime( 2049):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2401)
E/AndroidRuntime( 2049):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2417)
E/AndroidRuntime( 2049):    at android.app.ActivityThread.access$2100(ActivityThread.java:116)
E/AndroidRuntime( 2049):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794)
E/AndroidRuntime( 2049):    at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime( 2049):    at android.os.Looper.loop(Looper.java:123)
E/AndroidRuntime( 2049):    at android.app.ActivityThread.main(ActivityThread.java:4203)
E/AndroidRuntime( 2049):    at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime( 2049):    at java.lang.reflect.Method.invoke(Method.java:521)
E/AndroidRuntime( 2049):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)
E/AndroidRuntime( 2049):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:549)
E/AndroidRuntime( 2049):    at dalvik.system.NativeStart.main(Native Method)
E/AndroidRuntime( 2049): Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
E/AndroidRuntime( 2049):    at android.view.ViewRoot.setView(ViewRoot.java:460)
E/AndroidRuntime( 2049):    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)
E/AndroidRuntime( 2049):    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
E/AndroidRuntime( 2049):    at android.app.Dialog.show(Dialog.java:238)
E/AndroidRuntime( 2049):    at android.app.ProgressDialog.show(ProgressDialog.java:107)
E/AndroidRuntime( 2049):    at android.app.ProgressDialog.show(ProgressDialog.java:90)
E/AndroidRuntime( 2049):    at com.tastekid.TasteKid.YouTube.onCreate(YouTube.java:45)
E/AndroidRuntime( 2049):    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1123)
E/AndroidRuntime( 2049):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2364)
E/AndroidRuntime( 2049):    ... 11 more

Есть какие-нибудь идеи, почему это происходит?Я звоню сюда из onCreate способ.

Это было полезно?

Решение

Какую версию API вы используете?Если я прав насчет того, в чем проблема, то это было исправлено в Android 1.6 (версия API 4).

Это выглядит как ссылка на объект , которая getApplicationContext() возвращает просто указывает на null.Я думаю, у вас возникла проблема, похожая на ту, которая была у меня в том, что часть кода в onCreate() запускается до того, как фактически будет завершено построение окна.Это будет взлом, но попробуйте запустить новый поток через несколько сотен миллисекунд (IIRC:300-400, казалось, сработало для меня, но вам нужно будет повозиться), который открывает ваш ProgressDialog и запускает все остальное, что вам нужно (например.сетевой ввод-вывод).Что- то вроде этого:

@Override
public void onCreate(Bundle savedInstanceState) {
    // do all your other stuff here

    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            mProgressDialog = ProgressDialog.show(
               YouTube.this.getApplicationContext(), "",
               YouTube.this.getString(R.string.loading), true);

            // start time consuming background process here
        }
    }, 1000); // starting it in 1 second
}

Другие советы

Я использую Android версии 2.1 с API уровня 7.Я столкнулся с этой (или подобной) проблемой и решил ее с помощью этого:

Dialog dialog = new Dialog(this);

вместо этого:

Dialog dialog = new Dialog(getApplicationContext());

Надеюсь, это поможет :)

Для меня сработало изменение

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

Для

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

Странно то, что первый из них можно найти в Google tutorial, и люди получают сообщение об ошибке по этому поводу..

Я не думаю, что это проблема времени вокруг нулевого контекста приложения

Попробуйте расширить приложение внутри вашего приложения (или просто используйте его, если оно у вас уже есть).

public class MyApp extends Application

Сделайте экземпляр доступным как частный синглтон.Это никогда не бывает нулевым

private static MyApp appInstance;

Создайте статический помощник в MyApp (который будет использовать синглтон)

    public static void showProgressDialog( CharSequence title, CharSequence message )
{
    prog = ProgressDialog.show(appInstance, title, message, true); // Never Do This!
}

БУМ!!

Кроме того, ознакомьтесь с ответом Android engineer здесь: WindowManager исключение $BadTokenException

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

Теперь, я согласен, не имеет смысла, что метод принимает параметр контекста вместо Activity ..

Прочитав приведенные выше ответы, я обнаружил, что для моей ситуации следующая проблема устранена.

Это выдало ошибку

myButton.setOnClickListener(new OnClickListener(){
    public void onClick(View v) {
        MyDialogue dialog = new MyDialogue(getApplicationContext());
        dialog.show();              
    }
});

Основываясь на предыдущих ответах, в которых предполагалось, что контекст был неправильным, я изменил getApplicationContext(), чтобы извлечь контекст из представления, переданного методу buttons onClick.

myButton.setOnClickListener(new OnClickListener(){
    public void onClick(View v) {
        MyDialogue dialog = new MyDialogue(v.getContext());
        dialog.show();              
    }
});

Я не до конца понимаю работу Java, поэтому могу ошибаться, но я предполагаю, что для моей конкретной ситуации причина могла быть связана с тем фактом, что приведенный выше фрагмент был определен в абстрактном классе Activity;унаследованный и используемый многими Действиями, возможно, это способствовало тому факту, что getApplicationContext() не возвращает допустимый контекст??(Просто предположение).

Я создаю вид карты с детализированными наложениями.Я создавал свой itemizedoverlay следующим образом из моей MapActivity:

OCItemizedOverlay currentLocationOverlay = new OCItemizedOverlay(pin,getApplicationContext);

Я обнаружил, что получу "android.view.Исключение WindowManager $BadTokenException:Невозможно добавить окно - токен null не предназначен для исключения "приложения", когда был запущен метод onTap моего itemizedoverlay (когда местоположение отображается в mapview).

Я обнаружил, что если бы я просто передал 'this' вместо 'getApplicationContext()' своему конструктору, проблема исчезла.Это, кажется, подтверждает вывод alienjazzcat.странно.

Для действий, показанных в TabActivities, используйте getParent() Получить родителя()

final AlertDialog.Builder builder = new AlertDialog.Builder(getParent());

вместо того , чтобы

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

Для Android 2.2
Используйте этот код:

//activity is an instance of a class which extends android.app.Activity
Dialog dialog = new Dialog(activity);

вместо этого кода:

// this code produces an ERROR:
//android.view.WindowManager$BadTokenException: 
//Unable to add window -- token null is not for an application
Context mContext = activity.getApplicationContext();
Dialog dialog = new Dialog(mContext);

Замечание:Мой пользовательский диалог создается снаружи activity.onCreateDialog(int dialogId) способ.

Попробуй -

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

Была аналогичная проблема с фрагментами (совместимости), в которых использование getActivity() внутри ProgressDialog.show() разбивает его.Я бы согласился, что это из-за выбора времени.

Возможное исправление:

mContext = getApplicationContext();

if (mContext != null) {
    mProgressDialog = ProgressDialog.show(mContext, "", getString(R.string.loading), true);
}

вместо того, чтобы использовать

mProgressDialog = ProgressDialog.show(getApplicationContext(), "", getString(R.string.loading), true);

Разместите mContext как можно раньше, чтобы дать ему больше времени для восприятия контекста.По-прежнему нет гарантии, что это сработает, это просто снижает вероятность сбоя.Если это все еще не работает, вам придется прибегнуть к взлому таймера (что может вызвать другие проблемы с синхронизацией, такие как закрытие диалогового окна позже).

Конечно, если вы можете использовать this или ActivityName.this, это более стабильно , потому что this уже указывает на что-то.Но в некоторых случаях, например, с определенными архитектурами фрагментов, это не вариант.

(Для будущих ссылок)

Я думаю, это потому, что существуют различия в контексте приложения и контексте активности, как объяснено здесь: http://www.doubleencore.com/2013/06/context/

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

Для использования диалоговых окон внутри действий сделайте это следующим образом:

private Context mContext;
private AlertDialog.Builder mBuilder;

@Override
protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     mContext = this;

     //using mContext here refering to activity context
     mBuilder = new AlertDialog.Builder(mContext);
     //...
     //rest of the code
     //...
}

Для использования диалоговых окон внутри фрагментов сделайте это следующим образом:

private Context mContext;
private AlertDialog.Builder mBuilder;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
      View mRootView = inflater.inflate(R.layout.fragment_layout, container, false);
      mContext = getActivity();

      //using mContext here refering to fragment's hosting activity context
      mBuilder = new AlertDialog.Builder(mContext);
      //...
      //rest of the code
      //...
      return mRootView;
}

Вот и все ^_^

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

Базовый класс

public static Context myucontext; 

Первое действие, производное от базового класса

mycontext = this

Затем я использую mycontext вместо getApplicationContext при создании диалоговых окон.

AlertDialog alertDialog = new AlertDialog.Builder(mycontext).create();

Если вы вызываете ProgressDialog.show() во фрагменте, приведение mContext к Activity сработало для меня.

     ProgressDialog pd = new ProgressDialog((Activity) mContext);

Я реализовал диалоговое окно предупреждения для включения исключения в текущее представление activitty.Всякий раз, когда я давал подобное

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

Учитывая то же исключение из окна.Я пишу код для оповещения из onCreate().Настолько простой, что я использовал context = this; после setContentView() заявление в onCreate() метод.Принимается контекстная переменная как глобальная, подобная Context context;

Пример кода - это

static Context context;

 public void onCreate(Bundle savedInstanceState)  { 
        super.onCreate(savedInstanceState); 


        setContentView(R.layout.network); 
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

        context = this;
.......

Примером метода оповещения является

private void alertException(String execMsg){
        Log.i(TAG,"in alertException()..."+context);
        Log.e(TAG,"Exception :"+execMsg);
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
.......

У меня это работает нормально.На самом деле я искал эту ошибку в StackOverflow и нашел этот запрос.Прочитав все ответы на этот пост, я попробовал этот способ, и он работает.Я думал, что это простое решение для преодоления исключения.

Спасибо, Раджендар

если у вас возникли проблемы с groupActivity, не используйте это.PARENT - это статическое значение из Родительской ActivityGroup.

final AlertDialog.Builder builder = new AlertDialog.Builder(GroupActivityParent.PARENT);

вместо того , чтобы

final AlertDialog.Builder builder = new AlertDialog.Builder(getParent());

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

http://developer.android.com/guide/topics/ui/dialogs.html#ShowingADialog

Это распространенная проблема.Использование this вместо того , чтобы getApplicationContext() Это должно решить вашу проблему

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top