[英]android.view.WindowManager$BadTokenException error while creating dialog box
I am trying to create a Dialog Box from an Non activity Class. 我正在尝试从非活动类创建一个对话框。
This is my Code 这是我的代码
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
}
This is the error which I am getting 这是我得到的错误
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)
android.view.WindowManager $ BadTokenException:在Android.view.WindowManagerImpl.addView(WindowManagerImpl.java)的android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:282)的android.view.ViewRootImpl.setView(ViewRootImpl.java:574) :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.在android.app.Dialog.show(Dialog.java:298)在包装名称和类包装名称和类包装名称和类包装名称和类别在包装名称和CLASS.onBackPressed(Class.java:95)在android。 app.Activity.onKeyUp(Activity.java:2465)在android.view.KeyEvent.dispatch(KeyEvent.java:2646)的android.app.Activity.dispatchKeyEvent(Activity.java:2716)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)android.view.ViewRootImpl $ ViewPostImeInputStage.processKeyEvent(ViewRootImpl.java:4038)android.view.ViewRootImpl $ ViewPostImeInputStage.onProcess(ViewRootImpl.java:4000)at android.view.ViewRootImpl $ InputStage。在android.view.ViewRootImpl $ InputStage中传递(ViewRootImpl.java:3562)。 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)
onDeliverToNext(ViewRootImpl.java:3615)在android.view.ViewRootImpl $ InputStage.forward(ViewRootImpl.java:3581)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.inputmetho在android.view.ViewRootImpl $ AsyncInputStage.apply(ViewRootImpl.java:3755)android.view.ViewRootImpl $ InputStage.deliver(ViewRootImpl.java:3562)at android.view.ViewRootImpl $ InputStage.onDeliverToNext(ViewRootImpl.java:3615) )android.view.ViewRootImpl $ InputStage.forward(ViewRootImpl.java:3581)android.view.ViewRootImpl $ InputStage.apply(ViewRootImpl.java:3589)at android.view.ViewRootImpl $ InputStage.deliver(ViewRootImpl.java: 3562)在android.view.ViewRootImpl $ InputStage.onDeliverToNext(ViewRootImpl.java:3615)android.view.ViewRootImpl $ InputStage.forward(ViewRootImpl.java:3581)at android.view.ViewRootImpl $ AsyncInputStage.forward(ViewRootImpl.java) :3731)在android.view.inputmethod.InputMethodManager $ PendingEvent.run(InputMethodManager.java:2208)android.view.inputmethod.InputMethodManager.invokeFinishedInputEventCallback的android.view.ViewRootImpl $ ImeInputStage.onFinishedInputEvent(ViewRootImpl.java:3892) InputMethodManager.java:1849)在android.view.inputmetho d.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)
d.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)在android.app.AessT.Thread.main上的android.os.MessageQueue.next(MessageQueue.java:143)android.app.Looper.loop(Looper.java:122)。(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)在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:697)
Here is the scenario of the user 这是用户的场景
Activity A -->Opens Activity B-->User presses Back button in Activity B--> On Back button pressed a listener is sent to Activity A --> And then the Dialog Box shown is called. 活动A - >打开活动B - >用户按下活动B中的后退按钮 - >返回按钮按下一个监听器被发送到活动A - >然后调用显示的对话框。
I generally prefer using DialogFragment
instead of what you attempted in order to cut down on repetition. 我通常更喜欢使用
DialogFragment
代替您尝试的内容以减少重复。 Here is an example of a DialogFragment
with a custom layout which I have called R.layout.fragment_alert_dialog
: 这是一个带有自定义布局的
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();
}
}
It incorporates a Listener
just in case you need to be notified when the DialogFragment
is completed. 它包含一个
Listener
,以防您在DialogFragment
完成时需要得到通知。
First you need to implement the callback: implements AlertDialogFragment.AlertFinishedDialogListener{
首先,您需要实现回调:
implements AlertDialogFragment.AlertFinishedDialogListener{
In order to call the AlertDialogFragment
you do this from your Activity
(also Fragment
if necessary). 为了调用
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
问题
You can show dialogs from activity context only. 您只能从活动上下文显示对话框。 except TYPE_SYSTEM_ALERT or TYPE_APPLICATION_OVERLAY , which is not recommended if your app does not show emergency notifications to user.
除TYPE_SYSTEM_ALERT或TYPE_APPLICATION_OVERLAY外 ,如果您的应用未向用户显示紧急通知,则不建议使用此类型。
Solution
解
If you have activity context available then you can show dialog from any class like service
, broadcast receiver
, or even any class you imagine. 如果您有活动上下文,那么您可以显示任何类的对话框,如
service
, broadcast receiver
,甚至您想象的任何类。
Here is my workaround that can show dialog from any class like i said. 这是我的解决方法,可以显示任何类的对话,就像我说的那样。
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
}
});
}
}
Now you will implement to make this work. 现在你将实现这项工作。
1. make application class which you will register in android manifest application tag 1.制作你将在android manifest应用程序标签中注册的应用程序类
<application
android:name=".ApplicationContext"
...
>
...
</application>
2. In this application class you will hold live activity object. 2.在此应用程序类中,您将保存实时活动对象。 that will further useful for showing dialog.
这将对显示对话框更有用。
ApplicationContext.java 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;
}
}
Just one more step 再多一步
3. You will extend all your activity by this base activity class (You can edit your base activity if you already have one.) 3.您将通过此基本活动类扩展您的所有活动(如果已有基本活动,则可以编辑基本活动。)
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);
}
}
Here you go !!! 干得好 !!!
The issue you are having with the attempt to build your AlertDialog
in a separate class is you are passing the AlertDialog
the Context
of your Activity
. 你与尝试建立你遇到的问题
AlertDialog
在一个单独的类是要传递AlertDialog
的Context
您的Activity
。 You get the error because the AlertDialog
requires the WindowManager
from the Activity
which has the layout--not the Context
. 您得到错误,因为
AlertDialog
需要来自具有布局的Activity
的WindowManager
,而不是Context
。 This is because Activit
extends Context
... not the other way around. 这是因为
Activit
扩展了Context
......而不是相反。
In order to make your code work you need to provide the AlertDialog.Builder
access to the Activity
. 为了使您的代码工作,您需要提供
AlertDialog.Builder
访问Activity
。 So change your code to something like this: 所以将代码更改为以下内容:
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();
}
}
Now you can call the AlertDialog
from an Activity
lets say in this case MainActivity
like this: 现在你可以从一个
Activity
调用AlertDialog
,在这种情况下可以说MainActivity
如下:
TestDialog testDialog = new TestDialog(MainActivity.this);
testDialog.showDialog();
I have not tried this from a Fragment
, so I do not know whether this works from a Fragment
or whether you will continue to have issues with certain devices. 我没有从
Fragment
尝试这个,所以我不知道这是否可以从Fragment
或者您是否会继续遇到某些设备的问题。 For those reasons, I (and Google!) still strongly suggest that you use the DialogFragment
instead, because is has been especially designed for this scenario. 出于这些原因,我(和Google!)仍然强烈建议您使用
DialogFragment
,因为它是专为此方案设计的。 Take a look at the Google Docs.: 看看Google文档:
https://developer.android.com/guide/topics/ui/dialogs https://developer.android.com/guide/topics/ui/dialogs
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.