从我的主activity
开始,我需要调用内部类和类中的方法,我需要显示AlertDialog
。解除后,按下确定按钮后,转发到Google Play进行购买。
在大多数情况下,事情都很有效,但对于少数用户来说,它会在builder.show()
上崩溃,我可以看到"android.view.WindowManager$BadTokenException:
无法添加窗口"从崩溃日志。请建议。
我的代码非常像这样:
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();
}
}
}
}
我还看到另一个警告中的错误,我没有转发给任何其他activity
。它很简单:
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();
}
答案 0 :(得分:238)
android.view.WindowManager$BadTokenException: Unable to add window"
问题:
当应用尝试通知用户时会发生此异常 打开一个Dialog后台线程(AsyncTask)。
如果您尝试从后台线程修改UI(通常是 来自AsyncTask的onPostExecute())以及活动是否进入 完成阶段,即明确调用finish(),用户按下home Android或后退按钮或活动清理,然后你得到这个 错误。
原因:
此异常的原因是,正如异常消息所示, 活动已完成,但您正在尝试显示一个对话框 完成活动的背景。因为没有窗口 显示android运行时的对话框会抛出此异常。
<强>解决方案:强>
使用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();
}
}
}
}
更新:
窗口代币:
顾名思义,窗口标记是一种特殊类型的Binder标记 窗口管理器用来唯一标识窗口中的窗口 系统。窗口令牌对于安全性很重要,因为它们可以实现 恶意应用程序无法在窗口上绘制 其他应用。窗口管理器可以防止这种情况发生 要求应用程序将其应用程序的窗口令牌传递为 每个添加或删除窗口的请求的一部分。如果令牌没有 匹配,窗口管理器拒绝请求并抛出一个 的 BadTokenException 即可。没有窗口令牌,这是必要的 识别步骤是不可能的和窗口管理器 无法保护自己免受恶意应用程序的攻击。</ p>
真实场景:
当应用程序第一次启动时, ActivityManagerService 会创建一种特殊的窗口令牌 称为应用程序窗口令牌,唯一标识 应用程序的顶级容器窗口。活动经理给出 这个令牌同时应用程序和窗口管理器,以及 应用程序每次需要时都将令牌发送到窗口管理器 向屏幕添加新窗口。这确保了安全的交互 在应用程序和窗口管理器之间(通过制作它 不可能在其他应用程序之上添加窗口),以及 使活动管理者可以轻松地向活动管理员发出直接请求 窗口管理员。
答案 1 :(得分:17)
我有对话框显示功能:
void showDialog(){
new AlertDialog.Builder(MyActivity.this)
...
.show();
}
我收到此错误,我只需要在调用此对话框显示功能之前检查isFinishing()
。
if(!isFinishing())
showDialog();
答案 2 :(得分:9)
可能的原因是警报对话框的上下文。您可能已完成该活动,因此它尝试在该上下文中打开但已关闭。 尝试将该对话框的上下文更改为第一个活动,因为它将在最后完成。
例如
而不是这个。
AlertDialog alertDialog = new AlertDialog.Builder(this).create();
尝试使用
AlertDialog alertDialog = new AlertDialog.Builder(FirstActivity.getInstance()).create();
答案 3 :(得分:3)
第二次尝试从构建器创建AlterDailog,然后调用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();
}
答案 4 :(得分:0)
我正在onCreate
创建对话框并将其与show
和hide
一起使用。对我而言,根本原因并不是解雇onBackPressed
,而Home
活动正在完成。
@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
而没有关闭/取消我的对话框。
当我解除对话时,崩溃消失了。
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();
答案 5 :(得分:0)
试试这个:
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();
}
}
}
}
答案 6 :(得分:0)
我尝试解决了这个问题。
AlertDialog.Builder builder = new AlertDialog.Builder(
this);
builder.setCancelable(true);
builder.setTitle("Opss!!");
builder.setMessage("You Don't have anough coins to withdraw. ");
builder.setMessage("Please read the Withdraw rules.");
builder.setInverseBackgroundForced(true);
builder.setPositiveButton("OK",
(dialog, which) -> dialog.dismiss());
builder.create().show();
答案 7 :(得分:0)
就我而言,我重构了代码并将Dialog的创建放在单独的类中。我只交出了单击的View,因为View已经包含一个上下文对象。尽管都在MainThread上运行,但这导致了相同的错误消息。
然后,我也切换到活动的交接,并在对话框创建中使用其上下文 ->现在一切正常。
fun showDialogToDeletePhoto(baseActivity: BaseActivity, clickedParent: View, deletePhotoClickedListener: DeletePhotoClickedListener) {
val dialog = AlertDialog.Builder(baseActivity) // <-- here
.setTitle(baseActivity.getString(R.string.alert_delete_picture_dialog_title))
...
}
我,无法正确设置代码段的格式,抱歉:(
答案 8 :(得分:0)
我遇到了这个错误,但是我的是来自敬酒,而不是对话。
我的布局中有“活动”和“片段”。 Toast的代码在Activity类中。片段在活动之前加载。
我认为在上下文/活动完成初始化之前已命中Toast代码。我认为它是命令getApplicationContext()
Toast.makeText(getApplicationContext(), "onMenutItemActionCollapse called", Toast.LENGTH_SHORT).show();
答案 9 :(得分:-5)
有了这个全局变量的想法, 我在onCreate()中保存了MainActivity实例; Android global variable
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);
:)