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方法中调用此方法。


如果您正在使用Fragmentstackoverflow.com/questions/24825114/...
杨荣文

Answers:


42

您使用的是哪个API版本?如果我对问题是正确的,那么此问题已在Android 1.6(API版本4)中修复。

看起来getApplicationContext()返回的对象引用只是指向null。我认为您遇到的问题与我遇到的问题类似,其中的某些代码在onCreate()窗口实际完成构建之前就已在运行。这将是一个hack,但是尝试在几百毫秒内启动一个新的线程(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。我很确定任何UI操作都应该在UI线程中完成,因此在单独的线程中调用ProgressDialog.show()很容易成为一个大问题。还是觉得这很奇怪。
菲利克斯(Felix)

3
在我给您的示例中,您没有在另一个线程中执行UI操作,另一个线程只是回叫UI线程,告诉它打开对话框。
杰里米·洛根

这绝对很奇怪,而且完全是骇客,但这对我有用。我需要测试1.6中的错误,看看是否可以停止使用它。
杰里米·洛根

1
这不是“怪异”,也不是“彻底破解”,这是一种完全合法的方法!
KomodoDave

1
@KomodoDave我刚刚意识到我有同样的问题。但是,糟糕的时机已经到了。这是一个计时窗口,在某些情况下会间歇性地失败。成功的关键可能在于设置更短的计时器,检查应用程序是否准备就绪,然后重新进行操作直至完成。大概也限制尝试几次。
Jim Rush

129

我正在使用API​​级别7的Android版本2.1。我遇到了这个(或类似的)问题,并通过使用以下方法解决了:

Dialog dialog = new Dialog(this);

代替这个:

Dialog dialog = new Dialog(getApplicationContext());

希望这可以帮助 :)


4
我有一个类似的问题,但使用的是ActivityGroup。我能够解决此错误的唯一方法是使用getParent()代替。
brack 2010年

20
这如何回答他的问题?他问为什么第二个不起作用,而第一个不起作用。
Burkhard

3
-1,对于我们中的某些人来说,“ this”与“ getApplicationContext()”相同。
kellogs 2011年

开发2.1仍是有用的提示
Carlos P

64

对我来说,工作变化

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

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

奇怪的是,第一个可以在Google教程中找到,人们对此有所误解。


1
在onclick事件中发出警报的唯一解决方案
Tobias 2012年

这是正确的方法。除非绝对必要,否则切勿使用ApplicationContext,最重要的是,切勿使用它来显示UI元素。这就是活动(最终是片段)的目的。
Martin Marconcini

这是一个。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方法的View中检索上下文。

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

我不完全了解Java的工作原理,所以我可能是错的,但是我猜测对于我的特定情况,原因可能与上述代码段是在Abstract Activity类中定义的事实有关。由许多Activity继承和使用,可能导致getApplicationContext()没有返回有效上下文这一事实?(只是一个猜测)。


得分较高的解决方案可能适用于大多数情况,但是您的v.getContext()技术似乎可以解决最棘手的情况,例如我的情况。我的经验丰富的Java知识使我认为,来自onCreated方法的上下文与来自onClick方法的View的上下文并不完全相同。投票!
2014年

这挽救了我的一天!
亚历杭德罗·伦戈

6

我正在创建带有逐项叠加的地图视图。我正在从mapActivity创建我的itemizedoverlay:

OCItemizedOverlay currentLocationOverlay = new OCItemizedOverlay(pin,getApplicationContext);

我发现当触发我的itemizedoverlay的onTap方法时(当在地图视图上点击位置时),将出现“ android.view.WindowManager $ BadTokenException:无法添加窗口-令牌null不适用于应用程序”异常。

我发现,如果我只是将“ 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 2011年

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,以便有更多时间获取上下文。仍然不能保证它会起作用,它只是减少了崩溃的可能性。如果仍然无法使用,则您必须诉诸计时器破解(这可能会导致其他计时问题,例如稍后关闭对话框)。

当然,如果可以使用thisActivityName.this,那么它会更稳定,因为this已经指向了某个东西。但是在某些情况下,例如某些Fragment架构,这不是一个选择。



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 15'Dec



0

我已经实现了Alert Dialog,用于将异常抛出到当前的活动视图中。

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

警报出来的onCreate的考虑同一窗口Exception.I写代码()。所以,简单的我用context = this;setContentView()的声明onCreate() method中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);
.......

它对我来说很好。

谢谢,拉詹达


0

如果您对groupActivity有问题,请不要使用它。PARENT是父ActivityGroup中的静态对象。

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

代替

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.