天天看點

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方法。