buider.show()中的“android.view.WindowManager $ BadTokenException:无法添加窗口”

从我的主要活动中,我需要调用一个内部类和类中的方法,我需要显示AlertDialg,并按下确定button时closures它,并转发到谷歌播放购买。

在大多数情况下,事情是完美的,但是对于less数用户来说,它正在builder.show()上崩溃,我可以从崩溃日志中看到"android.view.WindowManager$BadTokenException:无法添加窗口”。 请build议。

我的代码非常像这样:

 public class classname1 extends Activity{ public void onCreate(Bundle savedInstanceState) { this.requestWindowFeature(Window.FEATURE_NO_TITLE); super.onCreate(savedInstanceState); setContentView(R.layout.<view>); //call the <className1> class to execute } private class classNamename2 extends AsyncTask<String, Void, String>{ protected String doInBackground(String... params) { } protected void onPostExecute(String result){ if(page.contains("error")) { AlertDialog.Builder builder = new AlertDialog.Builder(classname1.this); builder.setCancelable(true); builder.setMessage(""); builder.setInverseBackgroundForced(true); builder.setNeutralButton("Ok",new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton){ dialog.dismiss(); if(!<condition>) { try { String pl = ""; mHelper.<flow>(<class>.this, SKU, RC_REQUEST, <listener>, pl); } catch(Exception e) { e.printStackTrace(); } } } }); builder.show(); } } } } 

我也看到了另一个警报中的错误,我不转发任何其他活动。 这很简单:

 AlertDialog.Builder builder = new AlertDialog.Builder(classname1.this); builder.setCancelable(true); //if successful builder.setMessage(" "); builder.setInverseBackgroundForced(true); builder.setNeutralButton("Ok",new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton){ // dialog.dismiss(); } }); builder.show(); } 
 android.view.WindowManager$BadTokenException: Unable to add window" 

问题:

当应用程序尝试通过打开一个对话框从后台线程(AsyncTask)通知用户时,会发生此exception。

如果你试图从后台线程(通常从AsyncTask的onPostExecute())修改UI,并且如果活动进入完成阶段(即,)明确地调用finish(),用户按Home或Backbutton或由Android做的活动清理,然后你得到这个错误。

原因:

这个例外的原因是,正如exception消息所说,活动已经完成,但是您正在尝试显示一个对话框,其中包含完成的活动的上下文。 由于没有窗口显示android运行时会抛出这个exception。

解:

使用由Android调用的isFinishing()方法来检查此活动是否正在完成:是由Android完成的显式完成()调用还是活动清理。 通过使用这种方法,当活动结束时,很容易避免从后台线程打开对话框。

还要维护活动的weak reference (而不是强引用,以便在不需要的情况下可以销毁活动),并在使用此活动引用(即显示对话框)执行任何UI之前检查活动是否未完成。

例如

 private class chkSubscription extends AsyncTask<String, Void, String>{ private final WeakReference<login> loginActivityWeakRef; public chkSubscription (login loginActivity) { super(); this.loginActivityWeakRef= new WeakReference<login >(loginActivity) } protected String doInBackground(String... params) { //web service call } protected void onPostExecute(String result) { if(page.contains("error")) //when not subscribed { if (loginActivityWeakRef.get() != null && !loginActivityWeakRef.get().isFinishing()) { AlertDialog.Builder builder = new AlertDialog.Builder(login.this); builder.setCancelable(true); builder.setMessage(sucObject); builder.setInverseBackgroundForced(true); builder.setNeutralButton("Ok",new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton){ dialog.dismiss(); } }); builder.show(); } } } } 

更新:

窗口令牌:

顾名思义,窗口标记是窗口pipe理器用来唯一标识系统窗口的特殊types的活页夹标记。 窗口令牌对于安全性非常重要,因为它使得恶意应用程序不可能在其他应用程序的窗口之上绘图。 窗口pipe理器通过要求应用程序将其应用程序的窗口标记作为每个添加或删除窗口的请求的一部分来防止这种情况。 如果令牌不匹配,则窗口pipe理器拒绝该请求并抛出BadTokenException 。 没有窗口令牌,这个必要的识别步骤将不可能,窗口pipe理器将无法保护自己免受恶意应用程序的侵害。

一个真实的场景:

当应用程序第一次启动时, ActivityManagerService将创build一种称为应用程序窗口标记的特殊窗口标记,它唯一地标识应用程序的顶层容器窗口。 活动pipe理器将该令牌给予应用程序和窗口pipe理器,并且应用程序每次向屏幕添加新窗口时都将令牌发送给窗口pipe理器。 这确保了应用程序和窗口pipe理器之间的安全交互(通过使其无法在其他应用程序之上添加窗口),还使得活动pipe理器可以直接向窗口pipe理器发出请求。

可能的原因是警报对话框的上下文。 你可能会完成那个活动,所以试图在这个环境下打开,但是已经closures了。 尝试将该对话框的上下文更改为您的第一个活动,因为它不会结束。

例如

而不是这个。

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

尝试使用

 AlertDialog alertDialog = new AlertDialog.Builder(FirstActivity.getInstance()).create(); 

我有对话框显示function:

 void showDialog(){ new AlertDialog.Builder(MyActivity.this) ... .show(); } 

我得到这个错误,我只是在调用这个对话框显示函数之前检查isFinishing()

 if(!isFinishing()) showDialog(); 
  • 首先,您不能在不覆盖doInBackground的情况下扩展AsyncTask
  • 然后尝试从构build器创buildAlterDailog,然后调用show()。

     private boolean visible = false; class chkSubscription extends AsyncTask<String, Void, String> { protected void onPostExecute(String result) { AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); builder.setCancelable(true); builder.setMessage(sucObject); builder.setInverseBackgroundForced(true); builder.setNeutralButton("Ok", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { dialog.dismiss(); } }); AlertDialog myAlertDialog = builder.create(); if(visible) myAlertDialog.show(); } @Override protected String doInBackground(String... arg0) { // TODO Auto-generated method stub return null; } } @Override protected void onResume() { // TODO Auto-generated method stub super.onResume(); visible = true; } @Override protected void onStop() { visible = false; super.onStop(); } 

我在onCreate创build对话框,并使用它showhide 。 对于我来说,根本原因并不是在完成Home活动的onBackPressed解雇。

 @Override public void onBackPressed() { new AlertDialog.Builder(this) .setTitle("Really Exit?") .setMessage("Are you sure you want to exit?") .setNegativeButton(android.R.string.no, null) .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Home.this.finish(); return; } }).create().show(); 

我正在完成家庭活动onBackPressed没有closures/解散我的对话。

当我解散我的对话时,崩溃消失了。

 new AlertDialog.Builder(this) .setTitle("Really Exit?") .setMessage("Are you sure you want to exit?") .setNegativeButton(android.R.string.no, null) .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { networkErrorDialog.dismiss() ; homeLocationErrorDialog.dismiss() ; currentLocationErrorDialog.dismiss() ; Home.this.finish(); return; } }).create().show(); 

尝试这个 :

  public class <class> extends Activity{ private AlertDialog.Builder builder; public void onCreate(Bundle savedInstanceState) { this.requestWindowFeature(Window.FEATURE_NO_TITLE); super.onCreate(savedInstanceState); setContentView(R.layout.<view>); builder = new AlertDialog.Builder(<class>.this); builder.setCancelable(true); builder.setMessage(<message>); builder.setInverseBackgroundForced(true); //call the <className> class to execute } private class <className> extends AsyncTask<String, Void, String>{ protected String doInBackground(String... params) { } protected void onPostExecute(String result){ if(page.contains("error")) //when not subscribed { if(builder!=null){ builder.setNeutralButton("Ok",new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton){ dialog.dismiss(); if(!<condition>) { try { String pl = ""; mHelper.<flow>(<class>.this, SKU, RC_REQUEST, <listener>, pl); } catch(Exception e) { e.printStackTrace(); } } } }); builder.show(); } } } } 

用这个全局variables的想法,我保存MainActivity实例在onCreate(); Android全局variables

 public class ApplicationController extends Application { public static MainActivity this_MainActivity; } 

并打开这样的对话框。 有效。

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Global Var globals = (ApplicationController) this.getApplication(); globals.this_MainActivity = this; } 

在一个线程中,我打开这样的对话框。

 AlertDialog.Builder alert = new AlertDialog.Builder(globals.this_MainActivity); 
  1. 打开MainActivity
  2. 开始一个线程。
  3. 从线程 – >工作打开对话框。
  4. 点击“后退button”(onCreate将被调用并删除第一个MainActivity)
  5. 新的MainActivity将开始。 (并将它的实例保存为全局variables)
  6. 从第一个线程打开对话框 – >它将打开并工作。

:)

 AlertDialog.Builder builder = new AlertDialog.Builder(Activity.this); builder.setTitle("Invalid Data"); builder.setMessage("please enter valid name and mobile no."); builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel (); } }); AlertDialog alertDialog = builder.create(); alertDialog.show();