源码分析Android View加载及绘制流程

一、View的加载流程:

1、Activity调用setContentView方法,这里的getWindow是PhoneWindow,接着调用它的setContentView。

public void setContentView(@LayoutRes int layoutResID) {

        getWindow().setContentView(layoutResID);

        initWindowDecorActionBar();

    }

ContentParent为空则调用installDecor方法,创建一个DecorView,找到一个Id为com.android.internal.R.id.content的ViewGroup,设置给mContentParent。

public void setContentView(int layoutResID) {

        if (mContentParent == null) {

            installDecor();

        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {

            mContentParent.removeAllViews();

        }

        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {

            .....

            transitionTo(newScene);

        } else {

            mLayoutInflater.inflate(layoutResID, mContentParent);

        }

        .....

    }


图1 类关系图


图2 View树结构

2、在ActivityThread类的方法handleResumeActivity里面调用addView,将decorView添加到WindowManager中。

 //wm就是WindowManagerImpl

  wm.addView(decor, l);

//mGlobal就是WindowManagerGlobal

mGlobal.addView(view, params, mDisplay, mParentWindow);

root = new ViewRootImpl(view.getContext(), display);

在WindowManagerGlobal类中的addView方法里面调用rootViewImpl类的setView方法,开始绘制View树。

// do this last because it fires off messages to start doing things

root.setView(view, wparams, panelParentView);


图3 DecorView添加窗口的过程

二、View绘制流程

1、UI绘制流程经历了五个阶段,分别是预测量阶段,布局窗口阶段,最终测量阶段,布局控件树阶段,绘制阶段。

A、预测量阶段,会对控件树进行第一次测量,将会计算出控件树为显示其内容所需的尺寸,即期望的窗口尺寸,View及其子类的onMeasure方法将会沿着控件树依次得到回调。

B、布局窗口阶段,根据预测量的结果,通过IWindowSession.relayout方法向WMS请求调整窗口的尺寸等属性,将引发WMS对窗口进行重新布局,并将布局结果返回给ViewRootImpl。

C、最终测量阶段,将以窗口的实际尺寸对控件进行最终测量,View及其子类的onMeasure方法将会沿着控件树依次被回调。

D、布局控件树阶段,确定控件的位置,View及其子类的onLayout方法将会被回调。

E、绘制阶段,对控件树进行绘制,View及其子类的onDraw方法将会被回调。


图4 View绘制流程

三、实例演示

通过WindowManger类的addView将自定义悬浮窗口添加到DecorView上

private void installFloatingWindow() {

wm= (WindowManager)getSystemService(Context.WINDOW_SERVICE);

lp=newWindowManager.LayoutParams();

lp.type= WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;

lp.format= PixelFormat.RGBA_8888;

lp.flags= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;

lp.setTitle("Floating Window!");

lp.gravity= Gravity.LEFT| Gravity.TOP;

lp.x=0;

lp.y=0;

lp.width= Utils.getScreenWidth(this) /3;

lp.height= Utils.getScreenHeight(this) /3;

//用于检测状态栏高度.

intresourceId = getResources().getIdentifier("status_bar_height","dimen","android");

if(resourceId >0)

{

statusBarHeight= getResources().getDimensionPixelSize(resourceId);

}

LayoutInflater inflater = LayoutInflater.from(getApplication());

//获取浮动窗口视图所在布局.

floatLayout= (CustomToolBar) inflater.inflate(R.layout.floatlayout,null);

floatLayout.setToolBarClickListener(this);

floatLayout.setOnTouchListener(this);

wm.addView(floatLayout,lp);

}


图5 悬浮窗口Demo演示

代码下载地址

你可能感兴趣的:(源码分析Android View加载及绘制流程)