Android View的生命週期詳解
View生命週期相關方法:
onFinishInflate()
當View中所有的子控制元件均被對映成xml後觸發onMeasure( int , int )
確定所有子元素的大小onLayout( boolean , int , int , int , int )
當View分配所有的子元素的大小和位置時觸發onSizeChanged( int , int , int , int )
當view的大小發生變化時觸發onDraw(Canvas)
view渲染內容的細節onKeyDown( int , KeyEvent)
有按鍵按下後觸發onKeyUp( int , KeyEvent)
有按鍵按下後彈起時觸發onTrackballEvent(MotionEvent)
軌跡球事件onTouchEvent(MotionEvent)
觸屏事件onFocusChanged( boolean , int , Rect)
當View獲取或失去焦點時觸發onWindowFocusChanged( boolean )
當視窗包含的view獲取或失去焦點時觸發onAttachedToWindow()
當view被附著到一個視窗時觸發onDetachedFromWindow()
當view離開附著的視窗時觸發,Android123提示該方法和onAttachedToWindow()
是相反在這裡插入程式碼片
的。- onWindowVisibilityChanged( int ) 當視窗中包含的可見的view發生變化時觸發
綜上所述:View 的關鍵生命週期為 [改變可見性] --> 構造View
--> onFinishInflate
--> onAttachedToWindow
--> onMeasure
--> onSizeChanged
--> onLayout --> onDraw
--> onDetackedFromWindow
首先來看三分 建立view 的 日誌資訊 (自定義View 配置到xml檔案中):
android:visibility=gone
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
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
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))
輸入日誌資訊如下:
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
,會被忽略掉,比如如下程式碼:
@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
,如下程式碼:
@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
引數時報異常?異常資訊如下:
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
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
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
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 ):
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;
}
相關文章
- Android生命週期元件Lifecycle使用詳解Android元件
- View生命週期與Activity生命週期的關係View
- vue生命週期詳解Vue
- Vue的生命週期的詳解Vue
- Android Service生命週期 Service裡面的onStartCommand()方法詳解Android
- React 元件生命週期詳解React元件
- React元件生命週期詳解React元件
- 詳解Vue生命週期【上】Vue
- Android Activity生命週期Android
- 詳解 Vue 生命週期實現Vue
- Android官方架構元件Lifecycle:生命週期元件詳解&原理分析Android架構元件
- Android之各生命週期Android
- Servlet簡介及其生命週期詳解Servlet
- Android Service生命週期淺析Android
- Flutter仿Android生命週期LifecycleStateFlutterAndroid
- 詳解Spring中Bean的作用域與生命週期SpringBean
- Android Activity生命週期的一點感悟Android
- Android:聊聊 MVP 中 Presenter 的生命週期AndroidMVP
- 生命週期詳細解讀(含部分原始碼)原始碼
- Vue生命週期詳解+對應程式碼解析Vue
- Android 監聽生命週期工具庫Android
- Android中元件生命週期完全解析Android元件
- Android全面解析之Activity生命週期Android
- 擼擼Android的羊毛(二)----Activity生命週期Android
- Android知識重溫之生命週期Android
- Java Servlet詳解(體系結構+註解配置+生命週期)JavaServlet
- 生命週期
- Kubernetes容器生命週期 —— 鉤子函式詳解(postStart、preStop)函式REST
- viewController的生命週期ViewController
- Servlet的生命週期Servlet
- UIViewController的生命週期UIViewController
- Flutter 的生命週期Flutter
- Spring的生命週期Spring
- bean的生命週期Bean
- SQL的生命週期SQL
- Laravel的生命週期Laravel
- 類的生命週期
- 瞭解Android核心元件活動生命週期————旋轉螢幕Android元件