Android 不依赖于Activity的全局对话框Dialog

正常初始化对话框的写法

一般的Dialog对象初始化都需要依赖于Activity,如下

new AlertDialog.Builder(activity)
        .setTitle("野猿新一")
        .setMessage("我是对话框内容啦")
        .show();

 BroadcastReceiver如果是在Activity中注册的,用onReceive(Context context, Intent intent)方法的context参数来初始化Dialog是可以正常弹出对话框的。因为这里的context其实是一个Activity对象,如下所示:

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (context instanceof Activity) {
                    new AlertDialog.Builder(context)
                            .setTitle("野猿新一")
                            .setMessage("我是对话框内容啦")
                            .show();
                }
            }
        }, new IntentFilter("com.him.action"));
    }
}

 

会报错的写法

虽说AlertDialog.Builder(Context context)的参数是Context,但是如果传入的是非Activity的Context,比如说Application,就会报如下所示的错误

android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
        at android.view.ViewRootImpl.setView(ViewRootImpl.java:700)
        at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:289)
        at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:85)
        at android.app.Dialog.show(Dialog.java:298)
        at android.app.AlertDialog.show(AlertDialog.java:1128)
        at android.app.AlertDialog$Builder.show(AlertDialog.java:1008)
        at com.him.autosizingtest.MainActivity$1.onClick(MainActivity.java:21)
        at android.view.View.performClick(View.java:4918)
        at android.view.View$PerformClick.run(View.java:20399)
        at android.os.Handler.handleCallback(Handler.java:815)
        at android.os.Handler.dispatchMessage(Handler.java:104)
        at android.os.Looper.loop(Looper.java:194)
        at android.app.ActivityThread.main(ActivityThread.java:5869)
        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:1019)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:814)

所以以下的几种写法都会报错

new AlertDialog.Builder(activity.getApplication())
        .setTitle("野猿新一")
        .setMessage("我是对话框内容啦")
        .show();

new AlertDialog.Builder(activity.getApplicationContext())
        .setTitle("野猿新一")
        .setMessage("我是对话框内容啦")
        .show();

BroadcastReceiver如果是在Manifest中声明的,用onReceive(Context context, Intent intent)方法的context参数来初始化Dialog,一样还会报Unable to add window -- token null is not for an application错误。所以如下写法也不可行

public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        new AlertDialog.Builder(context)
                .setTitle("野猿新一")
                .setMessage("我是对话框内容啦")
                .show();
    }
}

// 在manifest中声明
<receiver android:name=".MyBroadcastReceiver">
    <intent-filter>
        <action android:name="com.him.action"/>
    </intent-filter>
</receiver>

全局Dialog

但是如果说有些情况下获取不到Activity对象,但是又想弹出Dialog呢?这时候用全局的Dialog是可以实现的。

只需要设置dialog为WindowManager.LayoutParams.TYPE_SYSTEM_ALERT类型

然后添加android.permission.SYSTEM_ALERT_WINDOW权限

Dialog dialog = new AlertDialog.Builder(activity.getApplicationContext())
        .setTitle("野猿新一")
        .setMessage("我是对话框内容啦")
        .create();
// 增加这句代码
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
dialog.show();

// 然后在manifest中添加权限
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

 

posted @ 2019-04-08 22:21  野猿新一  阅读(78)  评论(0编辑  收藏  举报