首页 > 解决方案 > 如何在Service android中显示警报对话框

问题描述

我是android新手,我想在服务中显示警报对话框,我使用了两种方法,如下所示

第一个没有布局

AlertDialog.Builder builder = new AlertDialog.Builder(MyService.this);
builder.setTitle("Test dialog");
builder.setMessage("Content");
builder.setNeutralButton("Ok", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
        System.exit(0);
    }
});
AlertDialog alert = builder.create();
alert.getWindow().setType(WindowManager.LayoutParams.TYPE_TOAST);
alert.show();

但我收到这样的错误,如下所示

E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.materialdialoginservice, PID: 25846
android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?
    at android.view.ViewRootImpl.setView(ViewRootImpl.java:993)
    at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:387)
    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:95)
    at android.app.Dialog.show(Dialog.java:344)
    at com.example.materialdialoginservice.MyService$3.run(MyService.java:98)
    at android.os.Handler.handleCallback(Handler.java:883)
    at android.os.Handler.dispatchMessage(Handler.java:100)
    at android.os.Looper.loop(Looper.java:224)
    at android.app.ActivityThread.main(ActivityThread.java:7561)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:995)

第二个带布局

AlertDialog.Builder builder = new AlertDialog.Builder(MyService.this);
View view = View.inflate(context, R.layout.activity_layout_view, null);
AlertDialog dialog = builder.create();
dialog.setView(view);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {//8.0 new features
    dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY - 1);
} else {
    dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_TOAST);
}
dialog.show();
Window dialogWindow = dialog.getWindow();
dialogWindow.setGravity(Gravity.CENTER);

我收到这样的错误,

E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.textstuff, PID: 27418
java.lang.RuntimeException: Unable to start service com.example.textstuff.MyService@134fed7 with Intent { cmp=com.example.textstuff/.MyService }: android.view.WindowManager$InvalidDisplayException: Unable to add window android.view.ViewRootImpl$W@124c071 -- the specified display can not be found
    at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:4196)
    at android.app.ActivityThread.access$2000(ActivityThread.java:233)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1946)
    at android.os.Handler.dispatchMessage(Handler.java:107)
    at android.os.Looper.loop(Looper.java:224)
    at android.app.ActivityThread.main(ActivityThread.java:7561)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:995)

像这样在清单文件中添加权限

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW"/>

标签: javaandroidkotlinserviceandroid-alertdialog

解决方案


只需删除:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // 8.0 new features
    dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY - 1);
} else {
    dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_TOAST);
}

并尝试:

dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT)

更新

在 Android 6.0 Marshmallow 中,用户必须明确允许您的应用“覆盖其他应用”。所以添加

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

现在在棉花糖中使用这个方法来处理运行时权限:

@TargetApi(Build.VERSION_CODES.M)
private void handleOverlaySettings() {
    final Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                                     Uri.parse("package:" + getPackageName()));
    try {
        startActivityForResult(intent, 11);
    } catch (ActivityNotFoundException e) {
        Log.e(TAG, e.getMessage());
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode) {
        case 11:
            final boolean overlayEnabled = Settings.canDrawOverlays(this);
            // handle the remaining logic
            break;
    }
}

现在显示服务中的对话框,如下所示:

    final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this, R.style.AppTheme_MaterialDialogTheme);

dialogBuilder.setTitle(R.string.dialog_title);
dialogBuilder.setMessage(R.string.dialog_message);
dialogBuilder.setNegativeButton(R.string.btn_back,
        new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        }
);

final AlertDialog dialog = dialogBuilder.create();
final Window dialogWindow = dialog.getWindow();
final WindowManager.LayoutParams dialogWindowAttributes = dialogWindow.getAttributes();

// Set fixed width (350dp) and WRAP_CONTENT height
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.copyFrom(dialogWindowAttributes);
lp.width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 350, getResources().getDisplayMetrics());
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
dialogWindow.setAttributes(lp);

// Set to TYPE_SYSTEM_ALERT so that the Service can display it
dialogWindow.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
dialogWindowAttributes.windowAnimations = R.style.DialogAnimation;
dialog.show();

现在一切就绪,这个解决方案应该可以工作了。祝你好运


推荐阅读