Android系统启动逻辑02

大家都知道在Android体系中Activity扮演了一个界面展示的角色,这也是它与android中另外一个很重要的组件Service最大的不同,但是这个展示的界面的功能是Activity直接控制的么?界面的布局文件是如何加载到内存并被Activity管理的?android中的View是一个怎样的概念?加载到内存中的布局文件是如何绘制出来的?

要想回答这些问题,我们就需要对android的布局加载  与  布局绘制流程有所了解,



activity的布局加载流程:

源码追踪:

activity完成启动后会调用我们Activity的onCreate方法,执行其中的setContentView(@LayoutRes int layoutResID)

  1. public void setContentView(@LayoutRes int layoutResID) {  
  2.         getWindow().setContentView(layoutResID);  
  3.         initWindowDecorActionBar();  
  4.     } 

调用getWindow获得mWindow的实例PhoneWindow,所以这里调用的其实是PhoneWindow的setConentView方法,

然后在phoneWindow的setContentView()方法中的installDecor()方法中的generateDecor()方法中初始化了mDector,mDector是一个DectorView对象,而DectorView继承与FrameLayout,所以这里的mDector其实就是一个FrameLayout对象。

在初始化mDector的installDecor()方法中,同时初始化mContentParent ,具体的初始化方法是 mContentParent= generateLayout(mDector),

在generateLayout(mDector)方法中{

    1. decor = mDector
     View in = mLayoutInflater.inflate(layoutResource, null);<strong><span style="color:#ff0000;">//系统布局文件,初始化为mContentRoot</span></strong>.  
  1.         decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));  
  2.         mContentRoot = (ViewGroup) in;  
  3. ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);

  1. return contentParent ;

}

通过对代码的分析,我们发现PhoneWindow中的几个成员变量:mDector,mContentRoot,mContentParent的关系 
mDector –> mContentRoot –> mContentParent(包含) 

在调用完setContentView()方法中的installDecor()方法后,接着调用mLayoutInflater.inflate(layoutResID, mContentParent); 

这个方法的含义就是将我们传递的客户端的layoutId对应的布局文件作为mContentParent的子View加载到内存中,

这样我们的layoutId作为mContentParent的子View,而mContentParent又是mContentRoot的子View,mContentRoot又是mDector的子View,通过LayoutInflater的inflate方法逐步加载到了内存中,而我们的Activity又持有自身的PhoneWindow的引用,这就相当于我们的Activity持有了我们定义的布局文件的引用,因而Activity的布局文件被加载到了内存中。

源码分析结束。


0、其实Activity对界面布局的管理是都是通过Window对象来实现的,Window对象,顾名思义就是一个窗口对象,而Activity从用户角度就是一个个的窗口实例,因此不难想象每个Activity中都对应着一个Window对象,而这个Window对象就是负责加载显示界面的。至于window对象是如何展示不同的界面的,那是通过定义不同的View组件实现不同的界面展示。

1、通过对代码的分析,我们发现PhoneWindow中的几个成员变量:mDector,mContentRoot,mContentParent的关系 
mDector –> mContentRoot –> mContentParent(包含) 

2、将我们传递的客户端的layoutId对应的布局文件作为mContentParent的子View加载到内存中,这样我们的layoutId作为mContentParent的子View,而mContentParent又是mContentRoot的子View,mContentRoot又是mDector的子View,通过LayoutInflater的inflate方法逐步加载到了内存中,而我们的Activity又持有自身的PhoneWindow的引用,这就相当于我们的Activity持有了我们定义的布局文件的引用,因而Activity的布局文件被加载到了内存中。

总结:

  • Activity的展示界面的特性是通过Window对象来控制的;

  • 每个Activity对象都对应这个一个Window对象,并且Window对象的初始化在启动Activity的时候完成,在执行Activity的onCreate方法之前;

  • 每个Window对象内部都存在一个FrameLayout类型的mDector对象,它是Acitivty界面的root view;

  • Activity中的window对象的实例是PhoneWindow对象,PhoneWindow对象中的几个成员变量mDector,mContentRoot,mContentParent都是View组件,它们的关系是:mDector –> mContentRoot –> mContentParent –> 自定义layoutView

  • LayoutInflater.inflate主要用于将布局文件加载到内存View组件中,也可以设定加载到某一个父组件中;

  • 典型的Activity的onCreate方法中需要调用super.onCreate方法和setContentView方法,若不调用super.onCreate方法,执行启动该Activity的逻辑会报错,若不执行setContentView的方法,该Activity只会显示一个空页面。


七、activity的布局绘制流程:

通过上一篇文章的分析,我们知道Activity是通过Window来控制界面的展示的,一个Window对象就是一个窗口对象,而每个Activity中都有一个相应的Window对象,所以说一个Activity对象也就可以说是一个窗口对象,而Window只是控制着界面布局文件的加载过程,那么界面布局文件的绘制流程是如何的呢?这篇文章主要就是顺着上篇文章的思路,看一下在android系统中Activity的布局文件是如何绘制的。

源码追踪:

Android体系在执行Activity的onResume方法之前会回调ActivityThread的handleResumeActivity方法:

handleResumeActivity方法中:执行了r.activity.makeVisible()方法

void makeVisible() { 
       if (!mWindowAdded) { 
           ViewManager wm = getWindowManager(); 
           wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;        
			}        
		mDecor.setVisibility(View.VISIBLE);    
	}
这里的ViewManager对象是通过getWindowManager()方法获取的,我们来看一下getWindowManager()方法的具体实现:

public WindowManager getWindowManager() {
        return mWindowManager;
    }
好吧,原来就是返回的Activity的mWindowManager的成员变量,那么这个mWindowManager的成员变量是什么时候赋值的呢?上一篇文章我们在Activity的attach方法方法中初始化了Activity的相关成员变量,这里也包括了mWindowManager,我们来看一下mWindowManager的赋值过程:

mWindowManager = mWindow.getWindowManager();
好吧,这里的Window.getWindowManager()方法是具体如何实现的呢?

public WindowManager getWindowManager() {
        return mWindowManager;
    }
那么这里的Window对象的mWindowManager成员变量是具体如何赋值的?
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);
    }
好吧,可以发现mWindowManager = ((WindowManagerImpl)vm).createLocalWindowManager(this)原来是在这里赋值的,所以一个Activity对应这一个新的Window,而这个Window对象内部会对应着一个新的WindowManager对象,我们接着往下看,那么createLoclWindowManager方法是如何实现的呢?

public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mDisplay, parentWindow);
    }

好吧,原来是new出了一个WindowManagerImpl对象,所以回到我们的Activity的makeVisible方法,ViewManager获取的是一个WindowManagerImpl对象,所以Window对象内部的WindowManager对象其实都是一个WindowManagerImpl的实例,都是而且从继承关系上可以看到:

WindowManagerImpl –> WindowManager –> ViewManager;

接着继续看

void makeVisible() {

 }的方法中的<span style="color: rgb(51, 51, 51); font-family: 'Source Code Pro', monospace; font-size: 14px; line-height: 22.5556px; white-space: pre; background-color: rgba(128, 128, 128, 0.0470588);">wm</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box; font-family: 'Source Code Pro', monospace; font-size: 14px; line-height: 22.5556px; white-space: pre; background-color: rgba(128, 128, 128, 0.0470588);">.addView</span><span style="color: rgb(51, 51, 51); font-family: 'Source Code Pro', monospace; font-size: 14px; line-height: 22.5556px; white-space: pre; background-color: rgba(128, 128, 128, 0.0470588);">(mDecor, getWindow()</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box; font-family: 'Source Code Pro', monospace; font-size: 14px; line-height: 22.5556px; white-space: pre; background-color: rgba(128, 128, 128, 0.0470588);">.getAttributes</span><span style="color: rgb(51, 51, 51); font-family: 'Source Code Pro', monospace; font-size: 14px; line-height: 22.5556px; white-space: pre; background-color: rgba(128, 128, 128, 0.0470588);">())</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box; font-family: 'Source Code Pro', monospace; font-size: 14px; line-height: 22.5556px; white-space: pre; background-color: rgba(128, 128, 128, 0.0470588);">;代码</span>

这里的mDector成员变量,通过上一篇文章的介绍,我们知道,它是Activity的界面根View,而getWindow.getAttrbutes方法是windowManager中定义的Params内部类,该内部类定义了许多的Window类型,由于这里的vm是WindowManagerImpl的实例,我们来看一下这里的addView的具体实现:

@Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mDisplay, mParentWindow);
    }

。。。。。。。待续






总结:

  • Activity执行onResume之前,在ActivityThread中执行Activity的makeVisible方法。

  • View的绘制流程包含了测量大小,测量位置,绘制三个流程;

  • Activty的界面绘制是从mDector即根View开始的,也就是从mDector的测量大小,测量位置,绘制三个流程;

  • View体系的绘制流程是从ViewRootImpl的performTraversals方法开始的;

  • View的测量大小流程:performMeasure –> measure –> onMeasure等方法;

  • View的测量位置流程:performLayout –> layout –> onLayout等方法;

  • View的绘制流程:onDraw等方法;

  • View组件的绘制流程会在onMeasure,onLayout以及onDraw方法中执行分发逻辑,也就是在onMeasure同时执行子View的测量大小逻辑,在onLayout中同时执行子View的测量位置逻辑,在onDraw中同时执行子View的绘制逻辑;

  • Activity中都对应这个一个Window对象,而每一个Window对象都对应着一个新的WindowManager对象(WindowManagerImpl实例);


八、应用进程context的创建流程:


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值