• Android绘制的Window和View


    Window作用是什么

    1. 管理View的显示和接受屏幕事件做传递处理,接受点击事件,window传递给DecorView
    2. Window本身是一个虚拟概念并没有实体,View树是Window的显示形式
    3. Window包含了addView方法来添加唯一的一个view
    4. Window有Z轴层级控制的效果,比如Dialog在PopupWindow之上,Toast在Dialog之上,app本身的Activity的Window层级,可以通过layoutParams.type来配置层级。
    5. Window通过softInputMode 可以控制软键盘伸缩方案
    6. Window通过flag控制显示,控制屏幕事件交互(交互范围)
    layoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
    
    • 1

    PhoneWindow&WindowManager创建的时机

    1. Activity启动方法在ActivityThread的performLaunchActivity
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
            ............
            ActivityInfo aInfo = r.activityInfo;
            }
    
    • 1
    • 2
    • 3
    • 4
    1. Activity内部构建attach
     activity.attach(appContext, this, getInstrumentation(), r.token,
                            r.ident, app, r.intent, r.activityInfo, title, r.parent,
                            r.embeddedID, r.lastNonConfigurationInstances, config,
                            r.referrer, r.voiceInteractor);
    
    • 1
    • 2
    • 3
    • 4
    1. attach方法中创建PhoneWindow和WindowManager
        //创建PhoneWindow,用于视图加载
            mWindow = new PhoneWindow(this);
            //将window事件通过回调接口,传递到Activity来处理
            mWindow.setCallback(this);
            mWindow.setOnWindowDismissedCallback(this);
            mWindow.getLayoutInflater().setPrivateFactory(this);
    //设置WindowManger
            mWindow.setWindowManager(
                    (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                    mToken, mComponent.flattenToString(),
                    (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    DecorView的创建时机

    1. onCreate方法中调用setContentView方法
    2. 调用PhoneWindow的setContentView方法
    3. setContentView实现
    public void setContentView(int layoutResID) {
            if (mContentParent == null) {
                installDecor();
            } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
                mContentParent.removeAllViews();
            }
            ................
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    installDecor方法最终创建DecorView

    private void installDecor() {
        mForceDecorInstall = false;
        if (mDecor == null) {
            // 这里创建了DecorView
            mDecor = generateDecor(-1);
            ...
        } else {
            mDecor.setWindow(this);
        }
        if (mContentParent == null) {
            // 对DecorView进行初始化,得到ContentView
            mContentParent = generateLayout(mDecor);
            ...
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    DecorView绑定到Window的时机,ViewRootIml创建时机

    1. ActivityThread执行handleResumeActivity
    2. handleResumeActivity调用makeVisiable(),获取到WindowManager,再执行addView方法
        void makeVisible() {
            if (!mWindowAdded) {
                //将DecorView添加到WindowManager
                ViewManager wm = getWindowManager();
                wm.addView(mDecor, getWindow().getAttributes());
                mWindowAdded = true;
            }
            mDecor.setVisibility(View.VISIBLE);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1. addView在WindowManagerIml中实现,创建了ViewRootIml来执行后续的测量绘制
      public void addView(View view, ViewGroup.LayoutParams params,
                Display display, Window parentWindow) {
           
                //ViewRootImpl 创建
                root = new ViewRootImpl(view.getContext(), display);
                .........
                root.setView()
                }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    1. setView()方法中会执行measure,layout,draw
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
            synchronized (this) {
                 .........
                  requestLayout();
    
                  .................
                //通过IPC,添加window交给WindowMangerServer
                        res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                                getHostVisibility(), mDisplay.getDisplayId(),
                                mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                                mAttachInfo.mOutsets, mInputChannel);
                 .........
              }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    整体时间线

    1. performLaunchActivity,
    2. 创建Activity,
    3. 执行attach方法创建WindowManager,PhoneWindow
    4. 执行onCreate
    5. 执行setContentView
    6. 创建DecorView
    7. 执行onResume
    8. WindowManager 添加DecorView
    9. addView中创建ViewRootImpl
    10. ViewRootImpl的setView执行requestLayout,在执行scheduleTraversals,在执行measure layout draw。

    Window和View是什么关系
    在测量Layout绘制之前需要有哪些准备工作
    View树什么时候建立好的
    addView什么时候能获取宽高
    DecorView什么时候创建的
    View什么时候能获取准确宽高

    参考:
    https://juejin.cn/post/6888688477714841608
    https://www.jianshu.com/p/96c9ca5431c7

  • 相关阅读:
    Shell 脚本编程——变量和运算符
    【洛谷】P3835 【模板】可持久化平衡树
    基于JavaWeb+SSM+Vue“鼻护灵”微信小程序系统的设计和实现
    Spring Boot Bean 注入的常用方式教程
    Win11如何删除升级包?Win11删除升级包的方法
    计算机原理-寻址方式
    考过HCIP依然转行失败,职业网工最看重的到底是什么
    C++ - 类型转换
    ZEMAX | 在OpticStudio中通过几何光线追迹来模拟杨氏双缝干涉实验
    数据库mysql详细教学
  • 原文地址:https://blog.csdn.net/baidu_16668271/article/details/133811606