android.view.WindowManager$BadTokenException 创建对话框时出错
android.view.WindowManager$BadTokenException error while creating dialog box
我正在尝试从非 activity Class 创建对话框。
这是我的代码
public static void ShowDialogBox(final Context con, final Listener list) {
AlertDialog.Builder dlgAlert = new AlertDialog.Builder(con);
dlgAlert.setMessage("TEXT");
dlgAlert.setTitle("TEXT");
dlgAlert.setPositiveButton("TEXT"),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
});
dlgAlert.setCancelable(false);
dlgAlert.create().show(); // THIS LINE GIVES ME AN ERROR
}
这是我遇到的错误
android.view.WindowManager$BadTokenException: at
android.view.ViewRootImpl.setView (ViewRootImpl.java:574) at
android.view.WindowManagerGlobal.addView
(WindowManagerGlobal.java:282) at
android.view.WindowManagerImpl.addView (WindowManagerImpl.java:85)
at android.app.Dialog.show (Dialog.java:298) at
PACKAGE NAME AND CLASS
PACKAGE NAME AND CLASS at
PACKAGE NAME AND CLASS
PACKAGE NAME AND CLASS at
PACKAGE NAME AND CLASS.onBackPressed
(Class.java:95) at android.app.Activity.onKeyUp
(Activity.java:2465) at android.view.KeyEvent.dispatch
(KeyEvent.java:2646) at android.app.Activity.dispatchKeyEvent
(Activity.java:2716) at
android.support.v7.internal.view.WindowCallbackWrapper.dispatchKeyEvent
(WindowCallbackWrapper.java:50) at
android.support.v7.app.AppCompatDelegateImplBase$AppCompatWindowCallbackBase.dispatchKeyEvent
(AppCompatDelegateImplBase.java:224) at
com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent
(PhoneWindow.java:2280) at
android.view.ViewRootImpl$ViewPostImeInputStage.processKeyEvent
(ViewRootImpl.java:4038) at
android.view.ViewRootImpl$ViewPostImeInputStage.onProcess
(ViewRootImpl.java:4000) at
android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:3562)
at android.view.ViewRootImpl$InputStage.onDeliverToNext
(ViewRootImpl.java:3615) at
android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:3581)
at android.view.ViewRootImpl$AsyncInputStage.forward
(ViewRootImpl.java:3698) at
android.view.ViewRootImpl$InputStage.apply (ViewRootImpl.java:3589)
at android.view.ViewRootImpl$AsyncInputStage.apply
(ViewRootImpl.java:3755) at
android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:3562)
at android.view.ViewRootImpl$InputStage.onDeliverToNext
(ViewRootImpl.java:3615) at
android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:3581)
at android.view.ViewRootImpl$InputStage.apply (ViewRootImpl.java:3589)
at android.view.ViewRootImpl$InputStage.deliver
(ViewRootImpl.java:3562) at
android.view.ViewRootImpl$InputStage.onDeliverToNext
(ViewRootImpl.java:3615) at
android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:3581)
at android.view.ViewRootImpl$AsyncInputStage.forward
(ViewRootImpl.java:3731) at
android.view.ViewRootImpl$ImeInputStage.onFinishedInputEvent
(ViewRootImpl.java:3892) at
android.view.inputmethod.InputMethodManager$PendingEvent.run
(InputMethodManager.java:2208) at
android.view.inputmethod.InputMethodManager.invokeFinishedInputEventCallback
(InputMethodManager.java:1849) at
android.view.inputmethod.InputMethodManager.finishedInputEvent
(InputMethodManager.java:1840) at
android.view.inputmethod.InputMethodManager$ImeInputEventSender.onInputEventFinished
(InputMethodManager.java:2185) at
android.view.InputEventSender.dispatchInputEventFinished
(InputEventSender.java:141) at
android.os.MessageQueue.nativePollOnce (Native Method) at
android.os.MessageQueue.next (MessageQueue.java:143) at
android.os.Looper.loop (Looper.java:122) at
android.app.ActivityThread.main (ActivityThread.java:5254) at
java.lang.reflect.Method.invoke (Native Method) at
java.lang.reflect.Method.invoke (Method.java:372) at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run
(ZygoteInit.java:902) at com.android.internal.os.ZygoteInit.main
(ZygoteInit.java:697)
这里是用户的场景
Activity A --> 打开 Activity B--> 用户在 Activity 中按下后退按钮 B--> 在按下后退按钮时,监听器是发送到 Activity A --> 然后调用显示的对话框。
我通常更喜欢使用 DialogFragment
而不是您尝试的方法,以减少重复。这是一个带有自定义布局的 DialogFragment
示例,我称之为 R.layout.fragment_alert_dialog
:
public class AlertDialogFragment extends DialogFragment {
private static final String ARG_TITLE = "title";
private static final String ARG_MESSAGE = "message";
private String title;
private String message;
boolean endSuccess = false;
private AlertFinishedDialogListener mListener;
public AlertDialogFragment() {
}
public static AlertDialogFragment newInstance(String title, String message) {
AlertDialogFragment fragment = new AlertDialogFragment();
Bundle args = new Bundle();
args.putString(ARG_TITLE, title);
args.putString(ARG_MESSAGE, message);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
title = getArguments().getString(ARG_TITLE);
message = getArguments().getString(ARG_MESSAGE);
}
}
@Override
public Dialog onCreateDialog(Bundle saveIntsanceState){
final Context context = getActivity();
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View rootView = inflater.inflate(R.layout.fragment_alert_dialog, null, false);
final TextView titleView = (TextView)rootView.findViewById(R.id.tvTitle);
final TextView messView = (TextView)rootView.findViewById(R.id.tvMessage);
titleView.setText(title);
messView.setText(message);
builder.setView(rootView)
// .setTitle(title)
.setPositiveButton(R.string.ok_button_dialog_title, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
endSuccess = true;
if(mListener == null) mListener = (AlertFinishedDialogListener) context;
mListener.onAlertFinishedDialog();
}
});
return builder.create();
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
try {
if(mListener == null) mListener = (AlertFinishedDialogListener) context;
}
catch (Exception ex){
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface AlertFinishedDialogListener {
void onAlertFinishedDialog();
}
}
它包含一个 Listener
以防万一您需要在 DialogFragment
完成时得到通知。
首先你需要实现回调:
implements AlertDialogFragment.AlertFinishedDialogListener{
为了调用 AlertDialogFragment
,您可以从 Activity
执行此操作(如有必要,也可以 Fragment
)。
private void startAlertDialogFragment(String title, String mess){
AlertDialogFragment alert = AlertDialogFragment.newInstance(title, mess);
alert.show(getFragmentManager(), "alertDialogFragment132");
}
@Override
public void onAlertFinishedDialog() {
Log.e(TAG, "onAlertFinishedDialog");
}
Problem
您只能显示来自 activity 上下文的对话框。 除了 TYPE_SYSTEM_ALERT or TYPE_APPLICATION_OVERLAY,如果您的应用不向用户显示紧急通知,则不推荐这样做。
Solution
如果您有 activity 上下文可用,那么您可以显示来自任何 class 的对话,例如 service
、broadcast receiver
,甚至您想象的任何 class .
这是我的解决方法,可以像我说的那样显示来自任何 class 的对话框。
Here is a snippet what i do to show dialog from any class. (Could it
be more simpler!)
import android.app.Dialog;
import android.content.DialogInterface;
public class SampleClass {
void anyMethod() {
Dialog dialog = ApplicationContext.getInstance().showDialog("title", "yourMessage", "Cancel", "Ok", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO: handle button 1 clicked
}
}, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO: handle button 2 clicked
}
});
}
}
现在您将执行此操作。
1.创建您将在 android 中注册的应用程序 class manifest application tag
<application
android:name=".ApplicationContext"
...
>
...
</application>
2。在此应用程序 class 中,您将持有实时 activity 对象。这对于显示对话框更有用。
ApplicationContext.java
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Application;
import android.content.DialogInterface;
public class ApplicationContext extends Application {
private static ApplicationContext mInstance;
private Activity liveActivity;
@Override
public void onCreate() {
super.onCreate();
mInstance = this;
}
@Override
public void onTerminate() {
super.onTerminate();
mInstance = null;
}
public static synchronized ApplicationContext getInstance() {
return mInstance;
}
public Activity getLiveActivity() {
return liveActivity;
}
public void setLiveActivity(Activity liveActivity) {
this.liveActivity = liveActivity;
}
/*
* Show Dialog with Title, Message, Button1, Button2 with Button1 and Button2 Listener
*/
public AlertDialog showDialog(String title, String msg,
String btn1, String btn2,
DialogInterface.OnClickListener listener1,
DialogInterface.OnClickListener listener2) {
if (liveActivity == null) return null;
AlertDialog.Builder builder = new AlertDialog.Builder(liveActivity)
.setTitle(title)
.setMessage(msg)
.setCancelable(false)
.setPositiveButton(btn1, listener1);
if (btn2 != null)
builder.setNegativeButton(btn2, listener2);
AlertDialog alert = builder.create();
alert.show();
return alert;
}
}
再走一步
3。您将通过此基数 activity class 扩展您的所有 activity(如果您已有基数,则可以编辑基数 activity。)
import android.support.v7.app.AppCompatActivity;
public class BaseActivity extends AppCompatActivity {
@Override
protected void onResume() {
super.onResume();
ApplicationContext.getInstance().setLiveActivity(this);
}
@Override
protected void onPause() {
super.onPause();
ApplicationContext.getInstance().setLiveActivity(null);
}
}
给你!!!
您尝试在单独的 class 中构建 AlertDialog
时遇到的问题是您正在传递 AlertDialog
Context
[=15] =].您收到错误是因为 AlertDialog
需要来自具有布局的 Activity
的 WindowManager
,而不是 Context
。这是因为 Activit
扩展了 Context
... 而不是相反。
为了使您的代码正常工作,您需要提供 AlertDialog.Builder
对 Activity
的访问权限。所以把你的代码改成这样:
public class TestDialog {
private static final String TAG = TestDialog.class.getSimpleName();
Activity mActivity;
public TestDialog(Activity activity){
mActivity = activity;
}
public void showDialog(){
AlertDialog.Builder b = new AlertDialog.Builder(mActivity);
b.setTitle("Title");
b.setMessage("message");
b.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Log.e(TAG, "showDialog : onClick");
}
});
b.create().show();
}
}
现在您可以从 Activity
调用 AlertDialog
让我们说在这种情况下 MainActivity
像这样:
TestDialog testDialog = new TestDialog(MainActivity.this);
testDialog.showDialog();
我没有在 Fragment
上尝试过,所以我不知道这是否适用于 Fragment
,或者您是否会继续遇到某些设备的问题。出于这些原因,我(和 Google!)仍然强烈建议您改用 DialogFragment
,因为它是专门为这种情况设计的。查看 Google 文档。:
我正在尝试从非 activity Class 创建对话框。
这是我的代码
public static void ShowDialogBox(final Context con, final Listener list) {
AlertDialog.Builder dlgAlert = new AlertDialog.Builder(con);
dlgAlert.setMessage("TEXT");
dlgAlert.setTitle("TEXT");
dlgAlert.setPositiveButton("TEXT"),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
});
dlgAlert.setCancelable(false);
dlgAlert.create().show(); // THIS LINE GIVES ME AN ERROR
}
这是我遇到的错误
android.view.WindowManager$BadTokenException: at android.view.ViewRootImpl.setView (ViewRootImpl.java:574) at android.view.WindowManagerGlobal.addView (WindowManagerGlobal.java:282) at android.view.WindowManagerImpl.addView (WindowManagerImpl.java:85)
at android.app.Dialog.show (Dialog.java:298) at PACKAGE NAME AND CLASS PACKAGE NAME AND CLASS at PACKAGE NAME AND CLASS PACKAGE NAME AND CLASS at PACKAGE NAME AND CLASS.onBackPressed (Class.java:95) at android.app.Activity.onKeyUp (Activity.java:2465) at android.view.KeyEvent.dispatch (KeyEvent.java:2646) at android.app.Activity.dispatchKeyEvent (Activity.java:2716) at android.support.v7.internal.view.WindowCallbackWrapper.dispatchKeyEvent (WindowCallbackWrapper.java:50) at android.support.v7.app.AppCompatDelegateImplBase$AppCompatWindowCallbackBase.dispatchKeyEvent (AppCompatDelegateImplBase.java:224) at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent (PhoneWindow.java:2280) at android.view.ViewRootImpl$ViewPostImeInputStage.processKeyEvent (ViewRootImpl.java:4038) at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess (ViewRootImpl.java:4000) at android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:3562) at android.view.ViewRootImpl$InputStage.onDeliverToNext (ViewRootImpl.java:3615) at android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:3581) at android.view.ViewRootImpl$AsyncInputStage.forward (ViewRootImpl.java:3698) at android.view.ViewRootImpl$InputStage.apply (ViewRootImpl.java:3589)
at android.view.ViewRootImpl$AsyncInputStage.apply (ViewRootImpl.java:3755) at android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:3562) at android.view.ViewRootImpl$InputStage.onDeliverToNext (ViewRootImpl.java:3615) at android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:3581) at android.view.ViewRootImpl$InputStage.apply (ViewRootImpl.java:3589) at android.view.ViewRootImpl$InputStage.deliver (ViewRootImpl.java:3562) at android.view.ViewRootImpl$InputStage.onDeliverToNext (ViewRootImpl.java:3615) at android.view.ViewRootImpl$InputStage.forward (ViewRootImpl.java:3581) at android.view.ViewRootImpl$AsyncInputStage.forward (ViewRootImpl.java:3731) at android.view.ViewRootImpl$ImeInputStage.onFinishedInputEvent (ViewRootImpl.java:3892) at android.view.inputmethod.InputMethodManager$PendingEvent.run (InputMethodManager.java:2208) at android.view.inputmethod.InputMethodManager.invokeFinishedInputEventCallback (InputMethodManager.java:1849) at android.view.inputmethod.InputMethodManager.finishedInputEvent (InputMethodManager.java:1840) at android.view.inputmethod.InputMethodManager$ImeInputEventSender.onInputEventFinished (InputMethodManager.java:2185) at android.view.InputEventSender.dispatchInputEventFinished (InputEventSender.java:141) at android.os.MessageQueue.nativePollOnce (Native Method) at android.os.MessageQueue.next (MessageQueue.java:143) at android.os.Looper.loop (Looper.java:122) at android.app.ActivityThread.main (ActivityThread.java:5254) at java.lang.reflect.Method.invoke (Native Method) at java.lang.reflect.Method.invoke (Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:902) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:697)
这里是用户的场景
Activity A --> 打开 Activity B--> 用户在 Activity 中按下后退按钮 B--> 在按下后退按钮时,监听器是发送到 Activity A --> 然后调用显示的对话框。
我通常更喜欢使用 DialogFragment
而不是您尝试的方法,以减少重复。这是一个带有自定义布局的 DialogFragment
示例,我称之为 R.layout.fragment_alert_dialog
:
public class AlertDialogFragment extends DialogFragment {
private static final String ARG_TITLE = "title";
private static final String ARG_MESSAGE = "message";
private String title;
private String message;
boolean endSuccess = false;
private AlertFinishedDialogListener mListener;
public AlertDialogFragment() {
}
public static AlertDialogFragment newInstance(String title, String message) {
AlertDialogFragment fragment = new AlertDialogFragment();
Bundle args = new Bundle();
args.putString(ARG_TITLE, title);
args.putString(ARG_MESSAGE, message);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
title = getArguments().getString(ARG_TITLE);
message = getArguments().getString(ARG_MESSAGE);
}
}
@Override
public Dialog onCreateDialog(Bundle saveIntsanceState){
final Context context = getActivity();
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View rootView = inflater.inflate(R.layout.fragment_alert_dialog, null, false);
final TextView titleView = (TextView)rootView.findViewById(R.id.tvTitle);
final TextView messView = (TextView)rootView.findViewById(R.id.tvMessage);
titleView.setText(title);
messView.setText(message);
builder.setView(rootView)
// .setTitle(title)
.setPositiveButton(R.string.ok_button_dialog_title, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
endSuccess = true;
if(mListener == null) mListener = (AlertFinishedDialogListener) context;
mListener.onAlertFinishedDialog();
}
});
return builder.create();
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
try {
if(mListener == null) mListener = (AlertFinishedDialogListener) context;
}
catch (Exception ex){
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface AlertFinishedDialogListener {
void onAlertFinishedDialog();
}
}
它包含一个 Listener
以防万一您需要在 DialogFragment
完成时得到通知。
首先你需要实现回调:
implements AlertDialogFragment.AlertFinishedDialogListener{
为了调用 AlertDialogFragment
,您可以从 Activity
执行此操作(如有必要,也可以 Fragment
)。
private void startAlertDialogFragment(String title, String mess){
AlertDialogFragment alert = AlertDialogFragment.newInstance(title, mess);
alert.show(getFragmentManager(), "alertDialogFragment132");
}
@Override
public void onAlertFinishedDialog() {
Log.e(TAG, "onAlertFinishedDialog");
}
Problem
您只能显示来自 activity 上下文的对话框。 除了 TYPE_SYSTEM_ALERT or TYPE_APPLICATION_OVERLAY,如果您的应用不向用户显示紧急通知,则不推荐这样做。
Solution
如果您有 activity 上下文可用,那么您可以显示来自任何 class 的对话,例如 service
、broadcast receiver
,甚至您想象的任何 class .
这是我的解决方法,可以像我说的那样显示来自任何 class 的对话框。
Here is a snippet what i do to show dialog from any class. (Could it be more simpler!)
import android.app.Dialog;
import android.content.DialogInterface;
public class SampleClass {
void anyMethod() {
Dialog dialog = ApplicationContext.getInstance().showDialog("title", "yourMessage", "Cancel", "Ok", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO: handle button 1 clicked
}
}, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO: handle button 2 clicked
}
});
}
}
现在您将执行此操作。
1.创建您将在 android 中注册的应用程序 class manifest application tag
<application
android:name=".ApplicationContext"
...
>
...
</application>
2。在此应用程序 class 中,您将持有实时 activity 对象。这对于显示对话框更有用。
ApplicationContext.java
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Application;
import android.content.DialogInterface;
public class ApplicationContext extends Application {
private static ApplicationContext mInstance;
private Activity liveActivity;
@Override
public void onCreate() {
super.onCreate();
mInstance = this;
}
@Override
public void onTerminate() {
super.onTerminate();
mInstance = null;
}
public static synchronized ApplicationContext getInstance() {
return mInstance;
}
public Activity getLiveActivity() {
return liveActivity;
}
public void setLiveActivity(Activity liveActivity) {
this.liveActivity = liveActivity;
}
/*
* Show Dialog with Title, Message, Button1, Button2 with Button1 and Button2 Listener
*/
public AlertDialog showDialog(String title, String msg,
String btn1, String btn2,
DialogInterface.OnClickListener listener1,
DialogInterface.OnClickListener listener2) {
if (liveActivity == null) return null;
AlertDialog.Builder builder = new AlertDialog.Builder(liveActivity)
.setTitle(title)
.setMessage(msg)
.setCancelable(false)
.setPositiveButton(btn1, listener1);
if (btn2 != null)
builder.setNegativeButton(btn2, listener2);
AlertDialog alert = builder.create();
alert.show();
return alert;
}
}
再走一步
3。您将通过此基数 activity class 扩展您的所有 activity(如果您已有基数,则可以编辑基数 activity。)
import android.support.v7.app.AppCompatActivity;
public class BaseActivity extends AppCompatActivity {
@Override
protected void onResume() {
super.onResume();
ApplicationContext.getInstance().setLiveActivity(this);
}
@Override
protected void onPause() {
super.onPause();
ApplicationContext.getInstance().setLiveActivity(null);
}
}
给你!!!
您尝试在单独的 class 中构建 AlertDialog
时遇到的问题是您正在传递 AlertDialog
Context
[=15] =].您收到错误是因为 AlertDialog
需要来自具有布局的 Activity
的 WindowManager
,而不是 Context
。这是因为 Activit
扩展了 Context
... 而不是相反。
为了使您的代码正常工作,您需要提供 AlertDialog.Builder
对 Activity
的访问权限。所以把你的代码改成这样:
public class TestDialog {
private static final String TAG = TestDialog.class.getSimpleName();
Activity mActivity;
public TestDialog(Activity activity){
mActivity = activity;
}
public void showDialog(){
AlertDialog.Builder b = new AlertDialog.Builder(mActivity);
b.setTitle("Title");
b.setMessage("message");
b.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Log.e(TAG, "showDialog : onClick");
}
});
b.create().show();
}
}
现在您可以从 Activity
调用 AlertDialog
让我们说在这种情况下 MainActivity
像这样:
TestDialog testDialog = new TestDialog(MainActivity.this);
testDialog.showDialog();
我没有在 Fragment
上尝试过,所以我不知道这是否适用于 Fragment
,或者您是否会继续遇到某些设备的问题。出于这些原因,我(和 Google!)仍然强烈建议您改用 DialogFragment
,因为它是专门为这种情况设计的。查看 Google 文档。: