Dialog显示和消失流程分析

本文所引用的代码为Android 5.0(API 22)版本

Dialog类实现了DialogInterface, Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener, Window.OnWindowDismissedCallback这个五个接口。比较常用到的三个接口:Window.Callback是接收屏幕touch事件;KeyEvent.Callback为接收键盘按键事件和实体键消息;Window.OnWindowDismissedCallback为接收窗口消失回调。

本文从Dialog的创建,隐藏,显示和移除步骤来分析相关的代码流程。最后补充了几个常见的异常分析。

请尊重博主劳动成果,转载请标明出处。

创建

看看构造方法代码:

    //提供给外部调用人口
    public Dialog(Context context) {
        this(context, 0, true);
    }

    //提供给外部调用人口
    public Dialog(Context context, int theme) {
        this(context, theme, true);
    }

    //真正执行初始化的构造方法
    Dialog(Context context, int theme, boolean createContextThemeWrapper) {
        if (createContextThemeWrapper) {
            if (theme == 0) {
                TypedValue outValue = new TypedValue();
                context.getTheme().resolveAttribute(com.android.internal.R.attr.dialogTheme, outValue, true);
                theme = outValue.resourceId;
            }
            mContext = new ContextThemeWrapper(context, theme);
        } else {
            mContext = context;
        }

        //获取WindowManagerImpl对象,这个对象一般为Activity的windowManger
        mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
        //创建PhoneWindow对象
        Window w = PolicyManager.makeNewWindow(mContext);
        //赋值,mWindow即PhoneWindow对象,不是WindowManger
        mWindow = w;
        设置Window.Callback回调
        w.setCallback(this);
        //window dismiss回调
        w.setOnWindowDismissedCallback(this);
        //调用Window的setWindowManager创建PhoneWindow内部的WindowMangerImpl
        w.setWindowManager(mWindowManager, null, null);
        //默认设置为居中
        w.setGravity(Gravity.CENTER);
        //接收异步消息的Handler
        mListenersHandler = new ListenersHandler(this);
    }

PolicyManager#makeNewWindow相关代码:
路径:/sources/android-22/com/android/internal/policy/PolicyManager.java

    public static Window makeNewWindow(Context context) {
        return sPolicy.makeNewWindow(context);
    }

sPolicy为Policy类的对象:
路径:/sources/android-22/com/android/internal/policy/impl/Policy.java

    public Window makeNewWindow(Context context) {
        return new PhoneWindow(context);
    }

Window的setWindowManager方法相关代码:

    public void setWindowManager(WindowManager wm, IBinder appToken, String appName) {
        setWindowManager(wm, appToken, appName, false);
    }

    public void setWindowManager(WindowManager wm, IBinder appToken, String appName, boolean hardwareAccelerated) {
        mAppToken = appToken;
        mAppName = appName;
        mHardwareAccelerated = hardwareAccelerated
                || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
        if (wm == null) {
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }

显示

show方法代码:

    public void show() {
        if (mShowing) {
  //dialog已调用过show方法,调用dismiss会设置为false
            if (mDecor != null) {
                if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
                    mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);
                }
                //显示Dialog的根View,即Dialog便可见
                mDecor.setVisibility(View.VISIBLE);
            }
            return;
        }

        mCanceled = false;

        if (!mCreated) {
            dispatchOnCreate(null);
        }

        onStart();
        //创建DecorView
        mDecor = mWindow.getDecorView();

        if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
            final ApplicationInfo info = mContext.getApplicationInfo();
            mWindow.setDefaultIcon(info.icon);
            mWindow.setDefaultLogo(info.logo);
            mActionBar = new WindowDecorActionBar(this);
        }

        //设置布局参数
        WindowManager.LayoutParams l = mWindow.getAttributes();
        if ((l.softInputMode
                & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) {
            WindowManager.LayoutParams nl = new WindowManager.LayoutParams();
            nl.copyFrom(l);
            nl.softInputMode |=
                    WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
            l = nl;
        }

        try {
            //添加到当前显示的窗口,便可以看见dialog
            mWindowManager.addView(mDecor, l);
            mShowing = true;
            //发送dialog显示消息
            sendShowMessage();
        } finally {
        }
    }

mDecor为DecorView对象,DecorView继承了FrameLayout。在Android 6.0以下版本,DecorView为PhoneWindow的内部类;6.0及以上版本,则被抽出,为一个独立的类。

我们在使用Dialog调用findViewById和setContentView方法,其实都是PhoneWindow中的方法在执行相应的操作。
Dialog中相关方法的代码:

    public View findViewById(int id) {
        return mWindow.findViewById(id);
    }

    public void setContentView(int layoutResID) {
        mWindow.setContentView(layoutResID);
    }

    public void setContentView(View view) {
        mWindow.setContentView(view);
    }

    public void setContentView(View view, ViewGroup.LayoutParams params) {
        mWindow.setContentView(view, params);
    }

    public void addContentView(View
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值