android 从全局的角度分析view的绘制机制(一)

    这篇博客会从全局的角度来一步步分析view的绘制机制。
    在这里先提前总结一下view的绘制流程,然后再对各个过程的源码进行分析(window,viewRoot,decorView):
    1.系统启动一个Activity的同时创建一个ViewRoot实例。
    2.Activity 在attach阶段生成一个PhoneWindow对象,它包含一个DecorView对象。
    3.在Activity执行onCreate中的setContentView之后,将读入的view加载进入第一张图的ContentViews区域。
    4.加载完毕后触发ViewRoot中的scheduleTraversals异步函数,从而进入ViewRootImpl的performTraversals函数,此时在performTraversals中会相继触发ViewRootImpl的 performMeasure, performLayout和performDraw方法,View的绘制从这里开始。

    5.在performMeasure中又会调用view的measure方法,performLayout和performDraw方法也会相继调用view的layout方法和draw方法。其中measure用来测量view的宽和高,layout用来确定view在父容器中的放置位置,而draw则用来负责将view绘制在屏幕上。

    6.对于测量过程,在ViewRootImpl的performMeasure方法中,实际上这里的view指的是顶级view,即DecorView,因此这里会相继调用DecorView的measure->onMeasure方法,在DecorView的onMeasure方法中又调用了FrameLayout的onMeasure方法,即:super.onMeasure(),接着就来到了viewGroup中,viewGroup会遍历其每一个子view,并调用子view的measure()来完成测量过程,而子view的测量又是和viewGroup的measureSpec以及子view的layoutParams来确定自身的宽和高的。

      接下来再对具体过程具体分析。首先在所有程序的入口main函数里会先创建activityThread:

public static void main(String[] args) {  
        Looper.prepareMainLooper();  
       // 创建ActivityThread实例  
        ActivityThread thread = new ActivityThread();  
        thread.attach(false);  
        .......
}
      而ActivityThead中的handleLaunchActivity中有两个重要的方法(至于ActivityThead将在另一篇博客中详细介绍),performLaunchActivity( )和handleResumeActivity( )。在performLaunchActivity( )中会调用activity的attach方法来建立一个窗口,而handleResumeActivity( )则会在启动activity的时候,将主窗口加入到windowManager中来实现窗口管理,来看部分源代码:
 private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
   ...........
         Activity a = performLaunchActivity(r, customIntent);

        if (a != null) {
         .............
         handleResumeActivity(r.token, false, r.isForward, !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
 }
    }
      函数首先调用ActivityThread类的成员函数performLaunchActivity来创建要启动的Activity组件。在创建Activity组件的过程中,还会为该Activity组件创建窗口对象和视图对象。Activity组件创建完成之后,就可以将它激活起来了,这是通过调用ActivityThread类的成员函数handleResumeActivity来执行的。接下来,我们首先分析ActivityThread类的成员函数performLaunchActivity,它主要功能就是创建一个activity组件实例,并且调用这个activity组件实例的成员函数onCreate来执行一些自定义的初始化工作(onCreate方法就是在这里被调用的!)
    接下来我们就来看看我们最熟悉的onCreate方法:
public void onCreate(Bundle savedInstanceState) {    
        super.onCreate(savedInstanceState);    
        setContentView(R.layout.main);    
    
        ......    
    }
public void setContentView(int layoutResID) {  
        getWindow().setContentView(layoutResID);  
    }  
     getWindow().setContentView(layoutResID)实际上就是调用PhoneWindow对象的setContentView方法:
 public void setContentView(int layoutResID) {
        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
        // decor, when theme attributes and the like are crystalized. Do not check the feature
        // before this happens.
        if (mContentParent == null) {
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }

        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                    getContext());
            transitionTo(newScene);
        } else {
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
        mContentParentExplicitlySet = true;
    }
      PhoneWindow类的成员变量mContentParent用来描述一个类型为DecorView的视图对象,或者这个类型为DecorView的视图对象的一个子视图对象,用作UI容器。当它的值等于null的时候,就说明正在处理的应用程序窗口的视图对象还没有创建。在这种情况下,就会调用成员函数installDecor来创建应用程序窗口视图对象。否则的话,就说明是要重新设置应用程序窗口的视图。在重新设置之前,首先调用成员变量mContentParent所描述的一个ViewGroup对象来移除原来的UI内容。
     如果假设此时mContentParent为nulll,此时会调用installDecor来创建DecorView视图对象,接着再通过调用PhoneWindow类的成员变量mLayoutInflater所描述的一个LayoutInflater对象的成员函数inflate来将参数layoutResID所描述的一个UI布局,并设置到前面所创建的应用程序窗口视图中去(DecorView),最后还会调用一个Callback接口的成员函数onContentChanged来通知对应的Activity组件,它的视图内容发生改变了。Activity组件自己实现了这个Callback接口,并且将这个Callback接口设置到了与它所关联的应用程序窗口对象的内部去,因此,前面实际调用的是Activity类的成员函数onContentChanged来发出一个视图内容变化通知。
     在installDecor函数中,会调用generateDecor来创建一个DecorView对象,并且保存在PhoneWindow类的成员变量mDecor中。紧接着installDecor又会调用generateLayout来根据当前应用程序窗口的Feature来加载对应的窗口布局文件(就是在layout目录下的布局文件),通过generateLayout能够创建一个应用程序窗口视图。
      这一步完成之后(即窗口视图创建起来之后),回到ActivityThread类的成员函数handleLaunchActivity中的handleResumeActivity之中,该方法用来激活正在启动的activity组件,由于是第一次激活该组件,因此在激活之前还会为该activity组件创建一个ViewRoot对象(主角登场),并将ViewRoot与前面所创建的应用程序视图窗口关联起来,以便后面通过该ViewRoot对象来控制应用程序窗口视图的UI展现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值