转载请标明出处:http://blog.csdn.net/sk719887916/article/details/39961201,作者:skay

对于接触安卓开不到一年的自己来说,总结下view的生命周期还是有非常重要的好处的,不仅表达了对view的理解,也可以给初学者学习参考;本文就粗略总结下view的加载机制,上一文中给大家粗略介绍了下安卓的绘图基础和原理,也偶尔提到了安卓的view是通过解析xml,然后变成java对象,再通过父类的canvas和paint绘制出来的,如果往上层理解,简单的概括下,就是在activty里通过这是ContenView方法,安卓WindownManger采用pul器l解析对应控件然后经过测量,摆放,最后绘制到界面上的,看了安卓关于view的源代码,也不难解释为何有的朋友在开发中获取键盘高度或者某一控件高度获取为零的原因,因为view在渲染时候并未测绘出来,而此时的实际高度必定为零。

View和ViewGroup


   view在安卓中充当具体可见视图东西,视图组建,其可称之做为ViewGroup的子类,填充到父容器中,ViewGruop是一组view的集合,用于存放和管理View的大小和具体位置功能,其可以理解为Activity和Fragmengt的关系,其两者生命周期非常类似。安卓的五大布局都是ViewGroup的子类,一些常用控件都是View的子类。 
view的周期如同就如建造一栋房子,我们首先需要筹备材料,然后进行实地测量,在进行具体挖地基,用准备的材料进行修建,最后交付人们居住。


一  View的大致生命周期:

主要:接收XML完成,进行测量,摆放,绘制,绑定到activty中 其自生还有很多API在不同场景触发。

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    // TODO Auto-generated method stub
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

@Override
protected void onLayout(boolean changed, int left, int top, int right,
        int bottom) {
    // TODO Auto-generated method stub
    super.onLayout(changed, left, top, right, bottom);
}
@Override

protected void onDraw(Canvas canvas) {
    // TODO Auto-generated method stub
}

@Override
protected void onFinishInflate() {
    // TODO Auto-generated method stub
    super.onFinishInflate();
}

@Override
protected void onAttachedToWindow() {
    // TODO Auto-generated method stub
    super.onAttachedToWindow();
}

1 onFinshInFlate()

    充当建房子时的材料接收准备,此材料收购任务交付 WindowManage.setContView进行实际加载和解析。 
用来接收在avtity中指定的布局文件,等待xml 解析器(pull)分别解析完所有子元素控件后触发,用于view或者ViewGroup进行之后一些列工作

  2  onMeasure()

   充当实际选址,和绘制工程图的作用。 
用来实际测量子元素的宽高 ,其里面子控件可以用Measue()方法来自我进行测绘,

   

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
	// TODO Auto-generated method stub

	    int width = 400;

	    int height = 800;

	    measure(width, height);

	    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
	}

如果在ViewGruop 我们可以对子布局依次进行测绘赋值,其具体会调用measure进行测绘,其内部会触发MeasureSpec.adjust转换, setMeasuredDimension进行参数设置,最后又会触发子View的onMeasure()的方法,使用递归进行轮训测绘 
知道没有任何Child的是指定参数,用MeasureCache来保存测好的值,便于后面的周期使用。

     

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    // TODO Auto-generated method stub

    int width = widthMeasureSpec;

    int height = 0;
    for (int i = 0; i < getChildCount(); i++) {
        View child = getChildAt(i);
        //获取子view的测量高度
        height = child.getMeasuredHeight();
        //获取子view的测量宽度
        width = child.getMeasuredWidth();
        //进行赋值测量值
        getChildAt(i).measure(width, height);

        height += height;
    }
    setMeasuredDimension(width, height);//当然我们可以直接设置宽高,无需调用父类onMessur的方法
    //super.onMeasure(width, height);
}

3   onLayout()

     充当更具工程图进行完地址,决定房间位置的作用。 
    用来进行子控件的具体摆放位置,其和测量的方法都是已经子控件在屏幕右上角的位置开始计算。
   

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int left = 0;
int top = 0;
int right = 60;
int bottom = 70;
layout(l, t, r, b);
} 


   如果在Viewgroup中,和上面的测量方法一样,依然采用遍历子控件,依次进行Layout(),到最后还依然递归到onLayout上来,因为不难理解,这里不再解释,值得强调的是,如果你在ViewGroup中重写 onLayout(),不能在继续super.onLayout()方法。因为ViewGruop已经没有可以存放的父类了。 onDraw()  充当我们的房子的的切墙和粉刷工作。安卓中用来做我们测好已经摆放好view的绘制工作,上篇文章中讲到,此方法结Canvas和Paint进行基础绘制工作,如果自定义控件 这些绘制需要我们自己去绘制 父类的onDraw()为抽象类,具体绘制情况基于你继承的父类控件类型(IamgeView,TextView等),而ViewGroup是有VIew特性的他是循环子类的onDraw()方法。这就解释了我们如果不继承任何类型的view,如果不重写Ondraw方法,即使已经做了测绘和布局摆放,也无法显示出来,因为系统无法识别你的view该调那个对应的ondraw()方法,其父类绘制源码也未做任何处理。


@Override

protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub

Paint paint = new Paint();
canvas.drawLine(startX, startY, stopX, stopY, paint);

super.onDraw(canvas);
}

其具体绘制图形细节请参来篇UI的绘制机制。

     5 onAttachedToWindow()

    充当房子修建完成,交付我们居住了。

当以上所有工作完成之后,触发此方法,用于绑定到setContView()的Activity上,此时生命周期交由Activity使用,但不代表view停止工作。onDetachedFromWindow()和此方法相反,当view被移除出去之后触发。

   二 view 的其他周期 


    以上是整个view必须触发的方法,但是更多的方法未必会部触发,接下来介绍下几个不被人熟知的API


@Override
	public void clearFocus() {
		// TODO Auto-generated method stub
		super.clearFocus();
	}
	 @Override
	public void invalidate(int l, int t, int r, int b) {
		// TODO Auto-generated method stub
		super.invalidate(l, t, r, b);
	}

	 @Override
	public void requestLayout() {
		// TODO Auto-generated method stub
		super.requestLayout();
	}

	 @Override
	public void forceLayout() {
		// TODO Auto-generated method stub
		super.forceLayout();
	}
	@Override
	protected Parcelable onSaveInstanceState() {
		// TODO Auto-generated method stub
		return super.onSaveInstanceState();
	}

	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		// TODO Auto-generated method stub
		super.onSizeChanged(w, h, oldw, oldh);
	}

	@Override
	protected void onAnimationStart() {
		// TODO Auto-generated method stub
		super.onAnimationStart();
	}

	@Override
	protected void onConfigurationChanged(Configuration newConfig) {
		// TODO Auto-generated method stub
		super.onConfigurationChanged(newConfig);
	}
	

1 invalidate()
此方法用来进行重绘工作,及时宽高和位置不变的情况也会可以主动调用。

2 requestLayout()
请求重新摆放,给予位置。

3 forceLayout()
清除已摆放的位置数据,释放view的具体坐标。

4 onSizeChanged()
在view尺寸发生变化是触发。一般父布局的大小不会发生变化的,手机屏幕固定

5 onConfigurationChanged()
横竖屏切换之后触发,此时view将从测绘,摆放和绘制重新走一遍。

6 onAnimationStart()
view有设置动画是触发,默认无动画,此方法对当前view截取bitmap镜像,不断调用draw进行绘制,

7 onSaveInstanceState()
保存当前的属性状态,便于切换view之前进行可序列传输,当我view不可见的时候,此时view的大小,位置和绘制的镜像位图,并未从内存中清除,当view再次显示的时候触发此方法。

到此大致规程已经熟知,

当view执行onMeasure()是遍历到存在子类的时候就会调用子子类Measure()的方法,子类在继续调用其onMeasure()方法,当其子类无子类的时候跳出交由父类继续执行onMeasure()方法,依次递归,直到所有子类全部测量完毕为止进行onMeasure()后继续onLayout,其如上图一样,继续遍历子view,如果有子类存在调用其Layout,子类内部调用onLayout(),依次递归。直到所有控件全部布局完毕,后开启ondraw()。

如下图:

当viewGroup里存在两个子类,一个view3和ViewGroup2,这是就会调用其两个子类的XXX方法,子类的XXX内部又会调用其子类的onXXx()。ViewGroup检测到View存在的时候又会调用其View1,.XXX(),依次递归。

ps:当然子控件的坐标不是按屏幕左上角原点位置计算,而是按父亲控件的左上角起点计算, 而事件中的触摸坐标不管是哪个view都是按屏幕原点计算的.

通过以上步骤,我们可以总结出,view的加载过程其实就是一个不断遍历其子节点再一次添加的过程,和其xml的解析如出一辙。欢迎大家阅读。

Android UI之View的加载机制(二)的更多相关文章

  1. Android之Android apk动态加载机制的研究(二):资源加载和activity生命周期管理

    转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/23387079 (来自singwhatiwanna的csdn博客) 前言 为了 ...

  2. Android View的加载过程

    大家都知道Android中加载view是从Activity的onCreate方法调用setContentView开始的,那么View的具体加载过程又是怎么的呢?这一节我们做一下分析. 首先追踪一下代码 ...

  3. Android View的加载流程

    什么是Activity? Activity是 用户操作的可视化界面:它为用户提供了一个放置视图和交互操作的窗口.采用setContentView的方法提供.因此,可以理解Activity.Window ...

  4. Android 的 so 文件加载机制

    本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 最近碰到一些 so 文件问题,顺便将相关知识点梳理一下. 提问 本文的结论是跟着 System.loadlibrary() 一层层源 ...

  5. Android ViewPager Fragment使用懒加载提升性能

     Android ViewPager Fragment使用懒加载提升性能 Fragment在如今的Android开发中越来越普遍,但是当ViewPager结合Fragment时候,由于Androi ...

  6. Android项目框架之图片加载框架的选择

    本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 从Android爆发以后,自定义的控件如EditTextWithDelete.ActionBar.P ...

  7. Android 插件开发,做成动态加载

    为什么需要插件开发: 相信你对Android方法数不能超过65K的限制应该有所耳闻,随着应用程序功能不断的丰富,总有一天你会遇到一个异常: Conversion to Dalvik format fa ...

  8. java加载机制整理

    本文是根据李刚的<疯狂讲义>作的笔记,程序有的地方做了修改,特别是路径,一直在混淆,浪费了好多时间!!希望懂的同学能够指导本人,感激尽............ 1.jvm 和 类的关系 当 ...

  9. 浅析dex文件加载机制

    我们可以利用DexClassLoader来实现动态加载dex文件,而很多资料也只是对于DexClassLoader的使用进行了介绍,没有深入讲解dex的动态加载机制,我们就借助于Android4.4的 ...

随机推荐

  1. 使用Myeclipse10.0自动生成搭建SSH框架(数据库表自动反向转换成Hibernate实体)实现用户登陆

    我这里使用的数据库是mysql5.0 数据是上课用的.这些都不是重点,重要的是学会这个方法: 创建好数据库: create database jboadefault character set utf ...

  2. HDFS的读数据过程分析

    我们继续在 FileSystem 类分析,读数据使用的是 open(-)方法,我们可以看到源码 FSDataInputStream in = fileSystem.open(new Path(&quo ...

  3. 关于LT分发系统的设计构想

    git地址 https://github.com/cxyxd/LtDistribution 背景 对tomcat做集群,在多机多tomcat的情况下,如果要更新代码,只能手动的将代码复制,粘贴,然后下 ...

  4. 【一天一道LeetCode】#137. Single Number II

    一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Given a ...

  5. Android 面向协议编程 体会优雅编程之旅

    Android中面向协议编程的深入浅出 http://blog.csdn.net/sk719887916/article/details skay编写 说起协议,现实生活中大家第一感觉会想到规则或者约 ...

  6. TensorFlow安装配置,茫茫人海中一瞥

    深度学习的框架,我们熟知的有caffe,torch和convnet.最近,Google又搞了一个TensorFlow,已经开源:http://www.tensorflow.org/.据说,谷歌的深度学 ...

  7. Ubuntu安装JDK与环境变量配置

    Ubuntu安装JDK与环境变量配置 一.getconf LONG_BIT 查看系统位数,并下载相应的jdk.我的系统是32位的,所以下载的jdk是:jdk-8u77-linux-i586.gz.并且 ...

  8. OpenCV空洞填充算法

    讨论帖: http://bbs.csdn.net/topics/391542633 在Matlab下,使用imfill可以很容易的完成孔洞填充操作,感觉这是一个极为常用的方法,然而不知道为什么Op ...

  9. 【面试必备】Swift&nbsp;面试题及其答案

    原文:Swift Interview Questions and Answers 原作者:Antonio Bello 原作者介绍: Antonio 拥有丰富的编程经验.他开始编程的时候,内存单位还是 ...

  10. (六十一)Xcode的git版本控制

    打开终端 1.为项目添加git: 首先到达项目的根目录内部,输入git init,初始化一个空的代码仓库(隐藏文件.get). 接下来使用git add . --all .表达把当前目录及子目录中的文 ...