Android View的生命周期詳解


View生命周期相關方法:

  1. onFinishInflate() 當View中所有的子控件均被映射成xml后觸發 
  2. onMeasure( int ,  int ) 確定所有子元素的大小 
  3. onLayout( boolean ,  int ,  int ,  int ,  int ) 當View分配所有的子元素的大小和位置時觸發     
  4. onSizeChanged( int ,  int ,  int ,  int ) 當view的大小發生變化時觸發  
  5. onDraw(Canvas) view渲染內容的細節  
  6. onKeyDown( int , KeyEvent) 有按鍵按下后觸發  
  7. onKeyUp( int , KeyEvent) 有按鍵按下后彈起時觸發  
  8. onTrackballEvent(MotionEvent) 軌跡球事件  
  9. onTouchEvent(MotionEvent) 觸屏事件  
  10. onFocusChanged( boolean ,  int , Rect) 當View獲取或失去焦點時觸發   
  11. onWindowFocusChanged( boolean ) 當窗口包含的view獲取或失去焦點時觸發  
  12. onAttachedToWindow() 當view被附着到一個窗口時觸發  
  13. onDetachedFromWindow() 當view離開附着的窗口時觸發,Android123提示該方法和  onAttachedToWindow() 是相反的。  
  14. onWindowVisibilityChanged( int ) 當窗口中包含的可見的view發生變化時觸發

綜上所述:View 的關鍵生命周期為 [改變可見性] --> 構造View --> onFinishInflate --> onAttachedToWindow --> onMeasure --> onSizeChanged --> onLayout --> onDraw --> onDetackedFromWindow

 

首先來看三分 創建view 的 日志信息 (自定義View 配置到xml文件中):

android:visibility=gone

 

?
1
2
3
4
5
6
7
8
9
10
03 - 25 19 : 56 : 55.934 : D/yyyyy( 11493 ): onVisibilityChanged--------=====
03 - 25 19 : 56 : 55.934 : D/yyyyy( 11493 ): construct 2 parameters .
03 - 25 19 : 56 : 55.934 : E/yyyyy( 11493 ): onFinishInflate
03 - 25 19 : 56 : 55.934 : D/yyyyy( 11493 ): onVisibilityChanged--------=====
03 - 25 19 : 56 : 55.934 : D/yyyyy( 11493 ): onVisibilityChanged--------=====
03 - 25 19 : 56 : 55.944 : D/yyyyy( 11493 ): onRtlPropertiesChanged--------=====
03 - 25 19 : 56 : 55.954 : D/yyyyy( 11493 ): onRtlPropertiesChanged--------=====
03 - 25 19 : 56 : 55.954 : E/yyyyy( 11493 ): onAttachedToWindow
03 - 25 19 : 56 : 55.954 : D/yyyyy( 11493 ): onWindowVisibilityChanged--------=====
03 - 25 19 : 56 : 55.974 : D/yyyyy( 11493 ): onWindowFocusChanged--------=====


android:visibility=invisible

 

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
03 - 25 19 : 57 : 38.204 : D/yyyyy( 11694 ): onVisibilityChanged--------=====
03 - 25 19 : 57 : 38.204 : D/yyyyy( 11694 ): construct 2 parameters .
03 - 25 19 : 57 : 38.204 : E/yyyyy( 11694 ): onFinishInflate
03 - 25 19 : 57 : 38.204 : D/yyyyy( 11694 ): onVisibilityChanged--------=====
03 - 25 19 : 57 : 38.204 : D/yyyyy( 11694 ): onVisibilityChanged--------=====
03 - 25 19 : 57 : 38.224 : D/yyyyy( 11694 ): onRtlPropertiesChanged--------=====
03 - 25 19 : 57 : 38.224 : D/yyyyy( 11694 ): onRtlPropertiesChanged--------=====
03 - 25 19 : 57 : 38.224 : E/yyyyy( 11694 ): onAttachedToWindow
03 - 25 19 : 57 : 38.224 : D/yyyyy( 11694 ): onWindowVisibilityChanged--------=====
03 - 25 19 : 57 : 38.224 : D/yyyyy( 11694 ): onMeasure , width : 1080  ; height: 1557
03 - 25 19 : 57 : 38.224 : D/yyyyy( 11694 ): onMeasure , width : 144  ; height: 1500
03 - 25 19 : 57 : 38.234 : D/yyyyy( 11694 ): onSizeChanged
03 - 25 19 : 57 : 38.234 : I/yyyyy( 11694 ): onLayout --> l: 0  ; r : 144  ; t: 57  ; b: 201  : changed : true
03 - 25 19 : 57 : 38.254 : D/yyyyy( 11694 ): onMeasure , width : 1080  ; height: 1557
03 - 25 19 : 57 : 38.254 : D/yyyyy( 11694 ): onMeasure , width : 144  ; height: 1500
03 - 25 19 : 57 : 38.254 : I/yyyyy( 11694 ): onLayout --> l: 0  ; r : 144  ; t: 57  ; b: 201  : changed : false
03 - 25 19 : 57 : 38.264 : D/yyyyy( 11694 ): onWindowFocusChanged--------=====


android:visibility=visible

 

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
03 - 25 19 : 55 : 15.434 : D/yyyyy( 11304 ): construct 2 parameters .
03 - 25 19 : 55 : 15.434 : E/yyyyy( 11304 ): onFinishInflate
03 - 25 19 : 55 : 15.434 : D/yyyyy( 11304 ): onVisibilityChanged--------=====
03 - 25 19 : 55 : 15.434 : D/yyyyy( 11304 ): onVisibilityChanged--------=====
03 - 25 19 : 55 : 15.454 : D/yyyyy( 11304 ): onRtlPropertiesChanged--------=====
03 - 25 19 : 55 : 15.454 : D/yyyyy( 11304 ): onRtlPropertiesChanged--------=====
03 - 25 19 : 55 : 15.454 : E/yyyyy( 11304 ): onAttachedToWindow
03 - 25 19 : 55 : 15.454 : D/yyyyy( 11304 ): onWindowVisibilityChanged--------=====
03 - 25 19 : 55 : 15.454 : D/yyyyy( 11304 ): onMeasure , width : 1080  ; height: 1557
03 - 25 19 : 55 : 15.454 : D/yyyyy( 11304 ): onMeasure , width : 144  ; height: 1500
03 - 25 19 : 55 : 15.464 : D/yyyyy( 11304 ): onSizeChanged
03 - 25 19 : 55 : 15.464 : I/yyyyy( 11304 ): onLayout --> l: 0  ; r : 144  ; t: 57  ; b: 201  : changed : true
03 - 25 19 : 55 : 15.474 : D/yyyyy( 11304 ): onMeasure , width : 1080  ; height: 1557
03 - 25 19 : 55 : 15.474 : D/yyyyy( 11304 ): onMeasure , width : 144  ; height: 1500
03 - 25 19 : 55 : 15.474 : I/yyyyy( 11304 ): onLayout --> l: 0  ; r : 144  ; t: 57  ; b: 201  : changed : false
03 - 25 19 : 55 : 15.474 : D/yyyyy( 11304 ): onDraw--------=====
03 - 25 19 : 55 : 15.484 : D/yyyyy( 11304 ): onWindowFocusChanged--------=====


1、從中不難看到view 默認為可見的 , 不是默認值時先調用 onVisibilityChanged , 但是此時該view 的任何位置信息都不知道。

 

2、可見性改變后才是調用帶有兩個參數的構造函數

3、從xml 文件中 inflate 完成

4、將view 加到 window 中 ( View 是gone 的 ,那么View創建生命周期也就結束 )

5、測量view的長寬 ( onMeasure )

6、定位View 在父View中的位置 ( onLayout )-->(View 是invisible , View 創建生命周期結束)

7、onDraw ( 只有可見的 View 才在 window 中繪制 )

 

在代碼中構造View:

setContentView(new CusView(this))輸入日志信息如下:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
03 - 25 20 : 37 : 51.284 : E/yyyyy( 12530 ): construct 1 parameter
03 - 25 20 : 37 : 51.294 : D/yyyyy( 12530 ): onVisibilityChanged--------=====
03 - 25 20 : 37 : 51.314 : D/yyyyy( 12530 ): onVisibilityChanged--------=====
03 - 25 20 : 37 : 51.314 : D/yyyyy( 12530 ): onRtlPropertiesChanged--------=====
03 - 25 20 : 37 : 51.314 : D/yyyyy( 12530 ): onRtlPropertiesChanged--------=====
03 - 25 20 : 37 : 51.314 : E/yyyyy( 12530 ): onAttachedToWindow
03 - 25 20 : 37 : 51.314 : D/yyyyy( 12530 ): onWindowVisibilityChanged--------=====
03 - 25 20 : 37 : 51.314 : D/yyyyy( 12530 ): onMeasure , width : 1080  ; height: 1557
03 - 25 20 : 37 : 51.314 : D/yyyyy( 12530 ): onSizeChanged
03 - 25 20 : 37 : 51.324 : I/yyyyy( 12530 ): onLayout --> l: 0  ; r : 1080  ; t: 0  ; b: 1557  : changed : true
03 - 25 20 : 37 : 51.324 : D/yyyyy( 12530 ): onMeasure , width : 1080  ; height: 1557
03 - 25 20 : 37 : 51.324 : I/yyyyy( 12530 ): onLayout --> l: 0  ; r : 1080  ; t: 0  ; b: 1557  : changed : false
03 - 25 20 : 37 : 51.324 : D/yyyyy( 12530 ): onDraw--------=====
03 - 25 20 : 37 : 51.344 : D/yyyyy( 12530 ): onWindowFocusChanged--------=====

 

從測試結果來看,默認情況下view的長和寬默認和父 view 的長和寬一致 。

 

雖然調用了onDraw 函數,但是在屏幕上卻看不到任何內容,什么原因?
當看不到任何內容時,請先檢查 View要繪制的內容是否制定。

 

為什么我指定了LayoutParameters,卻沒有效果?

在不恰當的生命周期中指定LayoutParameters,會被忽略掉,比如如下代碼:

 

?
1
2
3
4
5
6
7
8
9
10
@Override
     protected void onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         // setContentView(R.layout.activity_main);
         view = new CusView( this );
         view.setImageResource(R.drawable.ic_launcher);
         FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( 70 , 70 );
         view.setLayoutParams(params);
         setContentView(view);
     }

正確的方法應該是放到 onWindowFocusChanged 方法獲取到焦點后再指定LayoutParameters,如下代碼:

 

 

?
1
2
3
4
5
6
7
8
9
10
@Override
     public void onWindowFocusChanged( boolean hasFocus) {
         // TODO Auto-generated method stub
         super .onWindowFocusChanged(hasFocus);
         if (hasFocus) {
             view.setImageResource(R.drawable.ic_launcher);
             FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( 70 , 70 );
             view.setLayoutParams(params);
         }
     }


為什么我指定LayoutParameters參數時報異常?異常信息如下:

 

 

?
1
java.lang.ClassCastException: android.view.ViewGroup$LayoutParams cannot be cast to android.view.ViewGroup$MarginLayoutParams

 

 

java.lang.Object
? android.view.ViewGroup.LayoutParams
  ? android.view.ViewGroup.MarginLayoutParams

 

LayoutParameters的參數類型不對,從上面繼承關系可以看到MarginLayoutParameters擴展了ViewGroup的layoutParameters ,將其修改為任意支持margin動作的LayoutParameters 。


 

 

接下來我們看三份銷毀 View 的日志:

android:visibility=visible

 

?
1
2
3
03 - 25 21 : 15 : 35.404 : D/yyyyy( 14589 ): onWindowFocusChanged--------=====
03 - 25 21 : 15 : 35.484 : D/yyyyy( 14589 ): onWindowVisibilityChanged--------=====
03 - 25 21 : 15 : 35.504 : D/yyyyy( 14589 ): onDetachedFromWindow--------=====

 

android:visibility=gone

 

?
1
2
3
03 - 25 21 : 16 : 09.964 : D/yyyyy( 14736 ): onWindowFocusChanged--------=====
03 - 25 21 : 16 : 10.054 : D/yyyyy( 14736 ): onWindowVisibilityChanged--------=====
03 - 25 21 : 16 : 10.064 : D/yyyyy( 14736 ): onDetachedFromWindow--------=====

 

android:visibility=invisible

 

?
1
2
3
03 - 25 21 : 16 : 42.534 : D/yyyyy( 14860 ): onWindowFocusChanged--------=====
03 - 25 21 : 16 : 42.594 : D/yyyyy( 14860 ): onWindowVisibilityChanged--------=====
03 - 25 21 : 16 : 42.614 : D/yyyyy( 14860 ): onDetachedFromWindow--------=====


從以上內容可以看到,visibility屬性對view的銷毀流程沒有影響。

 

 

綜上所述:View 的關鍵生命周期為 [改變可見性] --> 構造View --> onFinishInflate --> onAttachedToWindow --> onMeasure --> onSizeChanged --> onLayout --> onDraw --> onDetackedFromWindow

 

 

最后給出一小段代碼用於在屏幕上拖動view(通過修改view的 layout ):

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private float mDownX, mDownY, x, y;
     private int dx, dy, il, ir, it, ib;
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         x = event.getX();
         y = event.getY();
         switch (event.getAction()) {
             case MotionEvent.ACTION_DOWN:
                 mDownX = event.getX();
                 mDownY = event.getY();
                 il = getLeft();
                 ir = getRight();
                 it = getTop();
                 ib = getBottom();
                 break ;
             case MotionEvent.ACTION_MOVE:
             case MotionEvent.ACTION_UP:
                 dx += Math.round(x - mDownX);
                 dy += Math.round(y - mDownY);
                 layout(il + dx, it + dy, ir + dx, ib + dy);
                 break ;
         }
         return true ;
     }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM