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()повертається, просто вказує на null. Я думаю, у вас виникають проблеми, подібні до тієї, яку я мав у тому, що якийсь код у програмі onCreate()запускається до того, як вікно насправді буде зроблено. Це стане хаком, але спробуйте запустити нову Тему за кілька сотень мілісекунд (IIRC: 300-400, здавалося, працює для мене, але вам потрібно буде повозитися), що відкриє ваш ProgressDialog і запустить все, що вам потрібно ( напр., мережа IO). Щось на зразок цього:

@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 ().
brack

20
Як це відповідає на його запитання? Він запитує, ЧОМУ другий не працює, тоді як перший робить.
Беркхард

3
-1, "це" так само, як "getApplicationContext ()" для деяких із нас.
kellogs

Ще корисна порада, що розробляється для 2.1
Carlos P

64

Для мене працювали змінюючись

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

до

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

Дивно те, що перше можна знайти в підручнику Google, і люди отримують помилку з цього приводу.


1
єдине рішення, що працює для мене з попередженням про подію onclick
Tobias

Це правильний спосіб зробити це. Ніколи не використовуйте 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

Однією з причин цієї помилки може бути спроба відображення вікна / діалогового вікна програми через контекст, який не є діяльністю.

Тепер, я погоджуюся, немає сенсу, що метод бере параметр контексту, а не активність.


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, тому я можу помилитися, але я здогадуюсь, що для моєї конкретної ситуації причина могла бути пов’язана з тим, що вищевказаний фрагмент був визначений у класі абстрактних занять; успадковано та використано багатьма видами діяльності, можливо, це сприяло тому, що getApplicationContext () не повертає дійсний контекст ?? (Просто здогадка).


Краще набрані рішення, ймовірно, працюють у більшості випадків, але ваша методика v.getContext (), здається, вирішує найбільш вперті випадки, як у мене. Мої емпіричні знання з Java підштовхують мене до думки, що контекст, що виходить із методу onCreate, не зовсім такий, як контекст, що виходить із перегляду методу onClick. Голосуйте!
Джош

Це врятувало мені день!
Алехандро Луенго

6

Я створюю подання карти з деталізованими накладками. Я створював подібний розділений елемент із моєї mapActivity:

OCItemizedOverlay currentLocationOverlay = new OCItemizedOverlay(pin,getApplicationContext);

Я виявив, що отримаю "android.view.WindowManager $ BadTokenException: Неможливо додати вікно - токен null не є додатком", коли був запущений метод onTap мого деталізованого шару (коли місце натискання на перегляді карти).

Я виявив, що якщо я просто передав "це" замість "getApplicationContext ()" моєму конструктору, проблема пішла. Це, мабуть, підтримує висновок Аліенязската. дивно.


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

Враховуючи той же Window Exception.Я пишу код для оповіщення про 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

якщо у вас є проблеми з груповою активністю, не використовуйте це. PARENT - статичний елемент з групи батьківської діяльності.

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.