当前位置:操作系统 > 安卓/Android >>

Android控件绘制过程

首先,在activity 类中(activity.java),我们可以看到两个变量,分别是:
        private Window mWindow;
        private WindowManager mWindowManager;
这两个变量在attach函数中进行赋值,
        mWindow = PolicyManager.makeNewWindow(this);
        mWindow.setWindowManager(null, mToken, mComponent.flattenToString());
        mWindowManager = mWindow.getWindowManager();
查看PolicyManager.makeNewWindow的具体实现可以看到,返回的是PhoneWindow对象(Policy.java中实现)。PhoneWindow是Window的派生类。跟踪setWindowManager我们可以得到WindowManager对象,并且这个对象是在系统唯一的,这个对象同样被赋值给Window的成员变量mWindowManager。一个Activity包含一个PhoneWindow,所有UI都被包含在PhoneWindow中。
    在PhoneWindow类中包含两个和View相关成员变量,分别是
        private DecorView mDecor;
        private ViewGroup mContentParent;
    我们知道,在Android平台上,UI界面是通过View和ViewGroup分层树进行定义的,如下图所示。
 
    最顶层的是ViewGroup,而DecorView就是PhoneWindow的View框架最顶层的根,DecorView是FrameLayout的派生类。在installDecor(PhoneWindow.java)中对mContentParent进行赋值
        mContentParent = generateLayout(mDecor);
    在generateLayout函数中(PhoneWindow.java)有如下实现:        
        View in = mLayoutInflater.inflate(layoutResource, null);
        decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
        return contentParent;
    mContentParent是从layoutResource中的布局xml中获得的,所有的activity用户新增加view都会被包含在这个对象当中。
    我们在新建一个activity时,往往在OnCreate中调用setContentView(R.layout.main)定义UI界面,跟踪setContentView发现实际上是调用了PhoneWindow的setContentView函数,在setContentView中,首先调用installDecor,对mDecor和mContentParent进行初始化,然后调用mLayoutInflater.inflate(layoutResID, mContentParent)从XML文中中生成相应的View并将用户新增的view添加到mContentParent对象当中。这个过程中会调用View的onFinishInflate。
    ViewRoot是Handler的派生类,在整个显示系统中最为关键,在android的UI结构中扮演的是一个中间者的角色,连接PhoneWindow跟WindowManagerService.
    WindowManger维护了一个三元组View, ViewRoot, LayoutParams数组,在ActivityThread类的handleResumeActivity中,有如下代码:
                r.window = r.activity.getWindow();
                View decor = r.window.getDecorView();
                decor.setVisibility(View.INVISIBLE);
                ViewManager wm = a.getWindowManager();
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (a.mVisibleFromClient) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);
                }
    首先获得WindowManger(通过跟踪发现a.getWindowManager()返回WindowManger对象),然后调用WindowManger的addView方法(WindowManagerImpl中实现)将PhoneWindow的DecorView添加到WindowManger中,同时为它创建一个ViewRoot对象。在addView中,将进行如下调用
                root.setView(view, wparams, panelParentView);
在ViewRoot的setView中将调用requestLayout,在requestLayout中会调用scheduleTraversals,而scheduleTraversals只是简单的发送处理消息DO_TRAVERSAL;我们知道ViewRoot是一个handler,所以接下来消息循环下一个将调用的就是ViewRoot的handleMessage。
    public void handleMessage(Message msg) {
        switch (msg.what) {
         case DO_TRAVERSAL:
            if (mProfile) {
                Debug.startMethodTracing("ViewRoot");
            }
            performTraversals();
            if (mProfile) {
                Debug.stopMethodTracing();
                mProfile = false;
            }
            break;
performTraversals函数相当复杂,完成了View框架从上到下的绘制,函数调用流程图如下:
 
    dispatchAttachedToWindow调用过程:
    首先,判断mFirst标志位,只有mFirst为true,即第一次调用的时候才调用ViewRoot对应的View的dispatchAttachedToWindow,这个View就是PhoneWindow中的DecorView。我们知道DecorView继承FrameLayout,是一个ViewGroup,dispatchAttachedToWindow实现如下:
            void dispatchAttachedToWindow(AttachInfo info, int visibility) {
                super.dispatchAttachedToWindow(info, visibility);
                visibility |= mViewFlags & VISIBILITY_MASK;
                final int count = mChildrenCount;
                final View[] children = mChildren;
                for (int i = 0; i < count; i++) {
                    children[i].dispatchAttachedToWindow(info, visibility);
                }
            }
View的dispatchAttachedToWindow中会调用onAttachedToWindow函数,各个控件可以重写onAttachedToWindow实现自己的操作。
    由上述代码可以知道,在View框架整个调用过程 ,如果是非叶节点,首先调用父类的dispatchAttachedToWindow,然后调用子节点的dispatchAttachedToWindow;如果是叶节点,则会调用View的dispatchAttachedToWindow,整个调用过程可以看成树的先序遍历。
    
    measure调用过程:
 
    DecorView的measure函数,首先调用View的measure实现,measure中会调用FrameLayout重写onMeasure,具体实现如下:
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final int count = getChildCount();
        int maxHeight = 0;
        int maxWidth = 0;
        // Find rightmost and bottommost child
        for (int i = 0; i < count; i++) {
补充:移动开发 , Android ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,