Activity七个基本的生命周期方法:onCreate、onStart、onResume、onPause、onStop、onDestory,这六个生命周期方法两两相互对应,外加一个onRestart方法。
自定义View时,常需要复写的方法:onMeasure、onLayout、onDraw以及onSizeChanged、onFinishInflate。
so,这些方法放一起啥顺序?
先蛮测下呗,在MainActivity中给七个生命周期方法打log;自定义FrameLayout和TextView的子类,即CustomViewGroup和CustomView,仅仅给五个生命周期方法打log;这两个自定义View直接放到Activity的xml布局中:
1. 启动MainActitity
顺序 | MainActivity | CustonViewGroup | CustomView |
---|---|---|---|
1 | onCreate before setContentView | ||
2 | CustonViewGroup(ctx, attrs) | ||
3 | CustomView(ctx, attrs) | ||
4 | onFinishInflate | ||
5 | onFinishInflate | ||
6 | onCreate after setContentView | ||
7 | onStart | ||
8 | onResume | ||
9 | onMeasure | ||
10 | onMeasure | ||
11 | onMeasure | ||
12 | onMeasure | ||
13 | onMeasure | ||
14 | onMeasure | ||
15 | onMeasure | ||
16 | onMeasure | ||
17 | onSizeChanged | ||
18 | onSizeChanged | ||
19 | onLayout | ||
20 | onLayout | ||
21 | onMeasure | ||
22 | onMeasure | ||
23 | onMeasure | ||
24 | onMeasure | ||
25 | onLayout | ||
26 | onLayout | ||
27 | onDraw | ||
28 | onDraw |
2. 更改ViewGroup/View初始化方法
以上是通过直接布局到布局文件中在setContentView中,通过系统加载布局文件初始化。如果布局文件没有CustomViewGroup和CustomView,而是在setContentView方法后,通过代码方式new出CustomViewGroup/CustomView,然后通过add方式将CustomView对象添加到CustomViewGroup对象中,最后将CustomViewGroup添加到MainActivityb根布局中呢?
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e(TAG, "onCreate: before setContentView");
setContentView(R.layout.activity_main);
Log.e(TAG, "onCreate: before addView");
RelativeLayout root = (RelativeLayout) findViewById(R.id.activity_main);
CustonViewGroup viewgroup = new CustonViewGroup(this);
CustomView view = new CustomView(this);
viewgroup.addView(view);
root.addView(viewgroup);
Log.e(TAG, "onCreate: after addView");
Log.e(TAG, "onCreate: after setContentView");
}
顺序 | MainActivity | CustonViewGroup | CustomView |
---|---|---|---|
1 | onCreate before setContentView | ||
2 | onCreate before addView | ||
3 | CustomViewGroup(ctx) | ||
4 | CustomView(ctx) | ||
5 | onCreate after addView | ||
6 | onCreate after setContentView | ||
7 | onStart | ||
8 | onResume |
以下同上面流程。
3. 总结1
通过布局方式添加控件,setContentView方法中,通过两个参数的构造方法初始化布局资源中所有的ViewGroup/View,并且回调了
onFinishInflate
方法。
同时也说明,
onFinishInflate
方法是在Activity的
onCreate
生命周期方法中调用的,但是如果是利用代码通过一个参数构造方法初始化ViewGroup/View此方法是没有被回调的。
public View(Context context){
...
}
public View(Context context, AttributeSet attrs){
...
}
protected void onFinishInflate() {
...
}
至于这个神奇的
setContentView
方法,可以参考
郭大神的Android LayoutInflater原理分析,带你一步步深入了解View(一)
鸿洋大神的鸿洋的 Android 源码解析 之 setContentView 一探究竟。
2. View的 onMeasure
、 onLayout
、 onDraw
以及 onSizeChanged
方法是在Activity的onResume方法执行后调用的。这也说明为什么在 onCreate
方法中不能直接获取到View的宽高,全是0啊。至于如何获取?恩,百度一大堆了。
onMeasure
onLayout
onDraw
onSizeChanged
onCreate
3. 至于为什么 onMeasure
这么厚颜无耻的重复调用,已经这些生命周期的调用坐等我搞懂。或者你们告诉我最好了。
onMeasure
4. 按下回退键
顺序 | MainActivity | CustonViewGroup | CustomView |
---|---|---|---|
1 | onPause | ||
2 | onStop | ||
3 | onDestroy |
5. 重新进入MainActivity并按下Home键
顺序 | MainActivity | CustonViewGroup | CustomView |
---|---|---|---|
1 | onPause | ||
2 | onStop |
6.回到MainActivity
顺序 | MainActivity | CustonViewGroup | CustomView |
---|---|---|---|
1 | onRestart | ||
2 | onStart | ||
3 | onResume | ||
4 | onDraw | ||
5 | onDraw |
7. ViewGroup父类方法:
这次我们在CustomViewGroup中多打几个log,看下ViewGroup对其子View生命周期方法的影响。
public class CustonViewGroup extends FrameLayout {
public static final String TAG = CustonViewGroup.class.getSimpleName();
//三个构造方法略
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.e(TAG, "onMeasure: before");
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Log.e(TAG, "onMeasure: after");
}
@Override
protected void onLayout(boolean b, int e, int i1, int i2, int i3) {
Log.e(TAG, "onLayout: before");
super.onLayout(b, e, i1, i2, i3);
Log.e(TAG, "onLayout: after");
}
@Override
protected void onDraw(Canvas canvas) {
Log.e(TAG, "onDraw: before");
super.onDraw(canvas);
Log.e(TAG, "onDraw: after");
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
Log.e(TAG, "onSizeChanged: before");
super.onSizeChanged(w, h, oldw, oldh);
Log.e(TAG, "onSizeChanged: after");
}
@Override
protected void onFinishInflate() {
Log.e(TAG, "onFinishInflate: before");
super.onFinishInflate();
Log.e(TAG, "onFinishInflate: after");
}
}
结果分析,流程基本跟第一次测试效果一样我们主要看CustomViewGroup和CustomView对应方法的顺序:
onFinishInflate
顺序 | CustonViewGroup | CustomView |
---|---|---|
1 | onFinishInflate | |
2 | onFinishInflate before | |
3 | onFinishInflate after |
onMeasure
顺序 | CustonViewGroup | CustomView |
---|---|---|
1 | onMeasure before | |
2 | onMeasure | |
3 | onMeasure after |
onSizeChanged和onLayout
顺序 | CustonViewGroup | CustomView |
---|---|---|
1 | onSizeChanged before | |
2 | onSizeChanged after | |
3 | onLayout before | |
3 | onSizeChanged | |
3 | onLayout | |
3 | onLayout after |
onDraw
顺序 | CustonViewGroup | CustomView |
---|---|---|
1 | onDraw before | |
2 | onDraw after | |
3 | onDraw |
8. 总结2
- ViewGroup的onFinishInflate、onSizeChanged、onDraw父类方法中没有调用子View的对应方法;
- ViewGroup的onMeasure父类方法中调用子View的对应方法;
- ViewGroup的onLayout父类方法中会调用子View的onSizeChanged和onLayout方法。