• AlertDialog 的context 不能是application的context


    昨天做了一个demo,静态注册的BroadcastrReceiver在onReceive方法里实现 alertdialog.

    但是,健哥说我的这个会报错,但是为什么没报错很奇怪,我也很奇怪,今早一来我就研究了一下alertdialog的坑。

    dialog 是类型同activity的应用窗口,都可以创建phonewindow实例。

    看看dialog的构造函数:

     Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
            // 忽略一些代码
            mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    
            final Window w = new PhoneWindow(mContext);
            mWindow = w;
            w.setCallback(this);
            w.setOnWindowDismissedCallback(this);
            w.setWindowManager(mWindowManager, null, null);//就是这句话。
            w.setGravity(Gravity.CENTER);
    
            mListenersHandler = new ListenersHandler(this);
        }

    setWindowManager(WindowManager wm, IBinder appToken, String appName) 第二个参数,我们设为null了,这个就是token,是个badtoken。(而在activity中,这个token被设为ActivityThread传过来的token。token呢是用来表示窗口的一个令牌,只有符合条件的token才能被WMS通过添加到应用上。)

    在Dialog的show方法中,

    public void show() {
            // 忽略一些代码
            mDecor = mWindow.getDecorView();
    
            WindowManager.LayoutParams l = mWindow.getAttributes();
             // 忽略一些代码
            try {
                mWindowManager.addView(mDecor, l);//返回manager的时候,如果tockon不为null会调用getSystemService(),为null,返回windowmanager时,会有一个badtockonexception的检测,会报出异常。
    mShowing = true; sendShowMessage(); } finally { } }

    Dialog最终也是通过系统的WindowManager把自己的Window添加到WMS上。在addView前,Dialog的token是null

    Dialog初化始时是通过Context.getSystemServer 来获取 WindowManager,会得到一个WindowManagerImpl的实例,这个实例里token也是null。之后在Dialog的show方法中将Dialog的DecorView(PhoneWindow.getDecorView())添加到WindowManager时会给token设置默认值还是null。返回windowmanager时,会有一个badtockonexception的检测,会报出异常。

     

    public Object getSystemService(@ServiceName @NonNull String name) {
            if (getBaseContext() == null) {
                throw new IllegalStateException(
                        "System services not available to Activities before onCreate()");
            }//因为一直传过来的context的tocken
    
            if (WINDOW_SERVICE.equals(name)) {
                return mWindowManager;
            } else if (SEARCH_SERVICE.equals(name)) {
                ensureSearchManager();
                return mSearchManager;
            }
            return super.getSystemService(name);
        }

    系统对TYPE_APPLICATION类型的窗口,要求必需是Activity的Token,不是的话系统会抛出BadTokenException异常。Dialog 是应用窗口类型,Token必须是Activity的Token。

    谷歌为什么要设置这个Token机制呢?

    为了防止bad Token啊。

    什么是BadToken呢?

    引用大神的解释:

    通过Token来验证WindowManager服务请求方是否是合法的。如果我们可以使用Application的Context,或者说Token可以不是Activity的Token,那么用户可能已经跳转到别的应用的Activity界面了,但我们却可以在别人的界面上弹出我们的Dialog,想想就觉得很危险。

    如你跳到了微信界面了,这时在后台的某个应用里调用Dialog的show,那么微信的界面上会显示一个Dialog,这个Dialog可能会让用户输入密码什么的,而用户完全无法区分是不是微信弹出的。

  • 相关阅读:
    头文件#ifndef #define #endif使用
    Django框架【form组件】
    数据库【mysql】之pymysql
    数据库【mysql篇】典型的一些练习题目
    Python开发【socket篇】解决粘包
    Python开发【内置模块篇】os模块
    Python开发【内置模块篇】日志模块
    Python开发【内置模块篇】configparser
    Python开发【内置模块篇】collections
    Python开发【内置模块篇】datetime
  • 原文地址:https://www.cnblogs.com/vitabebeauty/p/7125669.html
Copyright © 2020-2023  润新知