【问题标题】:Android: ProgressDialog.show() crashes with getApplicationContextAndroid:ProgressDialog.show() 使用 getApplicationContext 崩溃
【发布时间】:2010-12-06 10:00:03
【问题描述】:

我似乎无法理解为什么会这样。这段代码:

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

【问题讨论】:

标签: android progressdialog


【解决方案1】:

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

Dialog dialog = new Dialog(this);

而不是这个:

Dialog dialog = new Dialog(getApplicationContext());

希望这会有所帮助:)

【讨论】:

  • 我遇到了类似的问题,但使用的是 ActivityGroup。我能够解决此错误的唯一方法是改用 getParent()。
  • 这如何回答他的问题?他问为什么第二个不起作用,而第一个起作用。
  • -1,对于我们中的某些人来说,'this' 与 'getApplicationContext()' 相同。
  • 仍然是为 2.1 开发的有用提示
【解决方案2】:

对我来说改变了

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

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

奇怪的是,第一个可以在谷歌教程中找到,人们对此会出错..

【讨论】:

  • 唯一对我有用的解决方案,在 onclick 事件中发出警报
  • 这是正确的方法。除非绝对必要,否则切勿使用 ApplicationContext,最重要的是,切勿使用它来显示 UI 元素。这就是活动(以及最终的片段)的用途。
  • 就是这个。 this 如果您在例如单击侦听器中执行此操作,则单独使用将无法正常工作。
【解决方案3】:

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

看起来getApplicationContext() 返回的对象引用只是指向空值。我认为您遇到的问题与我遇到的问题类似,即 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
}

【讨论】:

  • 我使用的是 1.6。我很确定任何 UI 操作都应该在 UI 线程中完成,因此在单独的线程中调用 ProgressDialog.show() 很容易成为一个大问题。还是觉得这很奇怪。
  • 在我给您的示例中,您并没有在另一个线程中执行 UI 操作,另一个线程只是回调 UI 线程,告诉它打开对话框。
  • 这绝对很奇怪,而且完全是 hack,但它对我有用。我需要测试我在 1.6 中遇到的错误,看看我是否可以停止使用它。
  • 这不是“奇怪”,也不是“完全破解”,这是一种完全合法的方法!
  • @KomodoDave 我刚刚意识到我有同样的问题。然而,坏处在于计时器。这是在某些情况下等待间歇性失败的时间窗口。成功的关键可能在于设置一个更短的计时器,检查应用程序是否准备好,重新延迟操作直到它准备好。可能也会限制尝试的次数。
【解决方案4】:

我不认为这是围绕空应用程序上下文的时间问题

尝试在您的应用中扩展应用程序(或者如果您已经拥有,则直接使用它)

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

此错误的一个原因可能是尝试显示应用程序 通过不是 Activity 的上下文的窗口/对话框。

现在,我同意,该方法采用 Context 参数而不是 Activity..

【讨论】:

    【解决方案5】:

    阅读上述答案后,我发现针对我的情况,以下解决了该问题。

    这引发了错误

    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 的工作原理,所以我可能是错的,但我猜测对于我的具体情况,原因可能与上述 sn-p 是在抽象活动中定义的事实有关班级;许多活动继承和使用,也许这导致 getApplicationContext() 不返回有效上下文的事实? (只是猜测)。

    【讨论】:

    • 得分更高的解决方案可能适用于大多数情况,但您的 v.getContext() 技术似乎可以解决像我这样的最顽固的情况。我的经验 java 知识使我认为来自 onCreated 方法的上下文与来自 onClick 方法的视图的上下文并不完全相同。投票!
    • 这拯救了我的一天!
    【解决方案6】:

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

    OCItemizedOverlay currentLocationOverlay = new OCItemizedOverlay(pin,getApplicationContext);
    

    我发现当我的 itemizedoverlay 的 onTap 方法被触发时(在地图视图上点击位置时),我会收到“android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application”异常)。

    我发现如果我只是将“this”而不是“getApplicationContext()”传递给我的构造函数,问题就消失了。这似乎支持了alienjazzcat 的结论。很奇怪。

    【讨论】:

    • 谢谢,这正是我的问题。
    【解决方案7】:

    对于 TabActivities 中显示的活动,请使用 getParent()

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

    而不是

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

    【讨论】:

      【解决方案8】:

      适用于 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) 方法之外创建的。

      【讨论】:

        【解决方案9】:

        试试-

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

        【讨论】:

        • 当前活动在活动组内时需要
        【解决方案10】:

        在使用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 架构,这不是一种选择。

        【讨论】:

          【解决方案11】:

          (供以后参考)

          我认为这是因为应用程序上下文和活动上下文存在差异,如下所述:http://www.doubleencore.com/2013/06/context/

          这意味着我们不能使用应用程序上下文显示对话框。就是这样。

          【讨论】:

          • 对不起,如果我想根据应用程序上下文显示 hud,该怎么做?
          【解决方案12】:

          要在活动中使用对话框,请这样做:

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

          就是这样^_^

          【讨论】:

            【解决方案13】:

            我为解决这个问题所做的就是为我存储全局数据的所有活动创建一个基类。在第一个活动中,我将上下文保存在我的基类中的一个变量中,如下所示:

            基类

            public static Context myucontext; 
            

            从基类派生的第一个活动

            mycontext = this
            

            然后我在创建对话框时使用 mycontext 而不是 getApplicationContext。

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

            【讨论】:

            • 很遗憾这个解决方案没有得到更多的支持。在这里提出的所有可能的解决方案中,这是唯一对我有用的 AsyncTask
            【解决方案14】:

            如果您在片段中调用 ProgressDialog.show(),则将 mContext 转换为 Activity 对我有用。

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

            【讨论】:

              【解决方案15】:

              这是一个常见问题。 使用this 而不是getApplicationContext() 那应该可以解决您的问题

              【讨论】:

                【解决方案16】:

                我已经实现了警报对话框,用于将异常抛出到当前的活动视图。每当我这样给出时

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

                鉴于相同的窗口异常。我从 onCreate() 中编写警报代码。如此简单,我在 setContentView() 方法中的 setContentView() 语句之后使用了 context = this;。将上下文变量视为全局变量,如 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 上搜索了这个错误,我发现了这个查询。在阅读了这篇文章的所有回复后,我尝试了这种方式,所以它有效。我认为这是克服异常的简单解决方案。

                谢谢, 拉金达尔

                【讨论】:

                  【解决方案17】:

                  如果您在 groupActivity 上遇到问题,请不要使用它。 PARENT 是来自 Parent ActivityGroup 的静态变量。

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

                  而不是

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

                  【讨论】:

                    【解决方案18】:

                    对话框总是作为 Activity 的一部分创建和显示。您需要传入 Activity 上下文而不是 Application 上下文。

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

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 2015-05-14
                      • 2020-12-18
                      • 2014-04-30
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多