天天看点

Activity/ViewGroup/View生命周期方法

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啊。至于如何获取?恩,百度一大堆了。

3. 至于为什么

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

  1. ViewGroup的onFinishInflate、onSizeChanged、onDraw父类方法中没有调用子View的对应方法;
  2. ViewGroup的onMeasure父类方法中调用子View的对应方法;
  3. ViewGroup的onLayout父类方法中会调用子View的onSizeChanged和onLayout方法。