Android: ProgressDialog.show () вылетает из-за getApplicationContext


109

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

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метода.


Если вы используете Fragment, stackoverflow.com/questions/24825114/…
Yeo

Ответы:


42

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

Похоже, что getApplicationContext()возвращаемая ссылка на объект просто указывает на ноль. Я думаю, у вас возникла проблема, аналогичная той, что была у меня, в том, что часть кода в 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
}

6
Пользуюсь 1.6. Я почти уверен, что любые операции пользовательского интерфейса должны выполняться в потоке пользовательского интерфейса, поэтому вызов ProgressDialog.show () в отдельном потоке может легко стать большой проблемой. Все еще считаю это странным.
Феликс

3
В приведенном мною примере вы не выполняете операции пользовательского интерфейса в другом потоке, другой поток просто обращается к потоку пользовательского интерфейса, сообщая ему открыть диалоговое окно.
Джереми Логан,

Это определенно странно, и это полный взлом, но у меня это сработало. Мне нужно проверить ошибку, возникшую в 1.6, чтобы увидеть, могу ли я ПРЕКРАТИТЬ ее использовать.
Джереми Логан,

1
Это не «странно» и не «тотальный взлом», это совершенно законный подход!
KomodoDave

1
@KomodoDave Я только что понял, что у меня такая же проблема. Однако плохая хитрость - в таймере. Это временное окно, ожидающее периодического отказа в некоторых ситуациях. Ключ к успеху может заключаться в установке более короткого таймера, проверьте, готово ли приложение, повторно отложите действие, пока оно не будет готово. Возможно, ограничьте количество попыток.
Джим Раш

129

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

Dialog dialog = new Dialog(this);

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

Dialog dialog = new Dialog(getApplicationContext());

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


4
У меня была аналогичная проблема, но я использовал ActivityGroup. Единственный способ решить эту ошибку - использовать вместо нее getParent ().
брэк

20
Как это отвечает на его вопрос? Он спрашивает, ПОЧЕМУ второй не работает, а первый работает.
Burkhard

3
-1, «this» для некоторых из нас то же самое, что и «getApplicationContext ()».
kellogs

Тем не менее полезный совет, разрабатываемый для 2.1
Carlos P

64

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

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

к

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

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


1
единственное решение, работающее для меня с предупреждением внутри события onclick
Тобиас

Это правильный способ сделать это. Никогда не используйте ApplicationContext без крайней необходимости и, прежде всего, никогда не используйте его для отображения элементов пользовательского интерфейса. Вот для чего нужны действия (и в конечном итоге фрагменты).
Мартин Маркончини

Это тот самый. thisв одиночку не сработает, если вы делаете это, например, внутри прослушивателя кликов.
Айман Салах

23

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

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

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 здесь: WindowManager $ BadTokenException

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

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


10

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

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

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

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

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

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


Решения с более высокой оценкой, вероятно, работают в большинстве случаев, но ваш метод v.getContext (), похоже, решает самые сложные случаи, такие как мой. Мои эмпирические знания java заставляют меня думать, что контекст, исходящий от метода onCreated, не совсем то же самое, что контекст, исходящий из View метода onClick. Проголосуйте!
Джош

Это спасло мне день!
Алехандро Луенго

6

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

OCItemizedOverlay currentLocationOverlay = new OCItemizedOverlay(pin,getApplicationContext);

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

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


1
Спасибо, это именно то, в чем была моя проблема.
Кон

4

Для действий, отображаемых в TabActivities, используйте getParent ()

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

вместо того

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

3

Для 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)метода.


3

Пытаться -

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

Требуется, когда текущая активность находится внутри группы действий
htafoya

2

Была аналогичная проблема с (совместимостью) фрагментами, в которых использование 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уже на что-то указывает. Но в некоторых случаях, например, с некоторыми архитектурами фрагментов, это не вариант.


2

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

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

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


2

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

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;
}

Вот и все ^ _ ^


1

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

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

public static Context myucontext; 

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

mycontext = this

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

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

Жалко, что это решение больше не набирает голосов. Из всех возможных решений, представленных здесь, это единственное, что сработало для меня в AsyncTask
ckn

1

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

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

1

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


0

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

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

Учитывая же окна Exception.I кода записи для оповещения из OnCreate (). Так просто я использовал context = this;после setContentView()заявления в onCreate()method.Taken переменного контекста как глобальные , как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. Я нашел этот запрос. Прочитав все ответы на этот пост, я попробовал этот способ, поэтому он работает. Я подумал, что это простое решение для преодоления исключения.

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


0

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

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

вместо того

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.