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