Android View的生命周期、宽高初始化

View的生命周期函数执行顺序:

写一个类继承View,重写生命周期的各个回调函数,并且打印Log,以onDraw()函数为例这样打Log:

输出的Log如下:

V: construct  w/h: 0   0   mW/mH: 0   0
V: onFinishInflate w/h: 0   0   mW/mH: 0   0
V: onAttachedToWindow w/h: 0   0   mW/mH: 0   0
V: onWindowVisibilityChanged w/h: 0   0   mW/mH: 0   0
V: onVisibilityChanged w/h: 0   0   mW/mH: 0   0
V: onMeasure w/h: 0   0   mW/mH: 1080   2302
V: onMeasure w/h: 0   0   mW/mH: 1080   2400
V: onSizeChanged w/h: 1080   2400   mW/mH: 1080   2400
V: onLayout w/h: 1080   2400   mW/mH: 1080   2400
V: onDraw w/h: 1080   2400   mW/mH: 1080   2400
V: onDrawForeground w/h: 1080   2400   mW/mH: 1080   2400
V: onWindowFocusChanged w/h: 1080   2400   mW/mH: 1080   2400

View在初始化时onMeasure()函数执行了两次,这个函数里面用getWidth()和getHeight()是拿不到宽高的,getMeasureWidth()和getMeasureHeight()可以拿到宽高第一次拿到的宽高比第二次少98像数,看着这98像是通知栏的高度(此时的主题是隐藏通知栏的, 如下)

<item name="android:windowFullscreen">true</item> //满屏

于是去主题文件thems.xml把满屏的属性设置成false,这样onMeasure方法两次拿到的宽高是一样的,具体原因还得去挖源码

为什么getMeasureXXX()可以拿到宽高?看看源码里面的getMeasureWidth()方法:

mMeasureWidth是在setMeasuredDimension()去设置的,重写onMeasuer()方法的目的之一就是调用setMeasuredDimension()方法去设置这个值

 这里mMeasureWidth 和 MEASURED_SIZE_MASK 做了一个 &(按位与,也叫逻辑与)运算,MEASURED_SIZE_MASK是一个16进制数,他们在做运算时都会转成2进制数,可以看到它的低位都是f,那转成二进制数的时候低位全是1,在做&运算时可以起到限制mMeasureWidth大小的作用,如图:

---------------------------------------------------------------------------------------------------------------------------------

回归正题,从Log可以看出第一次能拿到view的宽高应是在onSizeChange()里面,但是在源码里头onSizeChange()这个函数没有写东西,它是由SizeChange()去调用的,调用sizeChange()的有四个函数setTop()、setLeft()、setRight()、setFrame()。 而 Layout()调用了setLFrame(),setFrame()函数在调用sizeChange()前设置了mLeft 和 mRight等属性,而getWidth()方法是返回View里的 (mRight-mLeft),所以在onSizeChange()函数里可以拿到宽高属性

View.java里setFrame()方法的代码片段:

在重写的onSizeChange()函数里打个断点再看看调用栈:

从这里看View宽高的初始化应该是在onSizeChange()里(或者说是在layout()里)

---------------------------------------------------------------------------------------------------------------------------------

把屏幕旋转后Log输出的内容:(跟上面view的初始化相比,多了红色的内容,多了onWindowVIsibility()和onDetachedFromWndow()这两个函数)

V: onWindowVisibilityChanged w/h: 2400   1080   mW/mH: 2400   1080
V: onDetachedFromWindow w/h: 2400   1080   mW/mH: 2400   1080

V: construct  w/h: 0   0   mW/mH: 0   0
V: onFinishInflate w/h: 0   0   mW/mH: 0   0
V: onAttachedToWindow w/h: 0   0   mW/mH: 0   0
V: onWindowVisibilityChanged w/h: 0   0   mW/mH: 0   0
V: onVisibilityChanged w/h: 0   0   mW/mH: 0   0
V: onMeasure w/h: 0   0   mW/mH: 1080   2400
V: onMeasure w/h: 0   0   mW/mH: 1080   2400
V: onSizeChanged w/h: 1080   2400   mW/mH: 1080   2400
V: onLayout w/h: 1080   2400   mW/mH: 1080   2400
V: onDraw w/h: 1080   2400   mW/mH: 1080   2400
V: onDrawForeground w/h: 1080   2400   mW/mH: 1080   2400
V: onWindowFocusChanged w/h: 1080   2400   mW/mH: 1080   2400

从Log看到view的整个生命周期函数都执行了一遍,因为转屏时Activity重建了,想要转屏时Activity不重建,在manifest文件对应的Activity加上这个配置:

这样的话执行的生命周期函数如下:

V: onMeasure w/h: 1080   2400   mW/mH: 2400   1080
V: onSizeChanged w/h: 2400   1080   mW/mH: 2400   1080
V: onLayout w/h: 2400   1080   mW/mH: 2400   1080
V: onDraw w/h: 2400   1080   mW/mH: 2400   1080
V: onDrawForeground w/h: 2400   1080   mW/mH: 2400   1080

可以看到onMeasure函数执行了一次,但是多转几次屏次次,有时候onMeasure函数会执行3次,具体原因没有去考究

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值