테스트, 아키텍처, 다 중요하지만 간과하는 부분이 있었다.
안드로이드 개발자라면 요구사항에 맞는 View 를 마음껏 그려내고 지연을 줄여 최적화 할 수 있어야한다.
오늘은 뷰가 그려지는 과정에 대해 이해해보자.
View Lifecycle
<참고>
https://proandroiddev.com/the-life-cycle-of-a-view-in-android-6a2c4665b95e
Custom View 를 만들다보면 View Lifecycle 를 마주할 때가 있다.
View Lifecycle 에 대해 알아보자.
안드로이드 컴포넌트, 프레그먼트와 마찬가지로 View 또한 Lifecycle 을 갖는다.
View Constructor
View 를 생성하는 방법은 다음과 같다. xml 파일에서 속성을 set 하고 싶으면 AttributeSet 이 필요하다.
View(Context context)
View(Context context, @Nullable AttributeSet attrs)
View(Context context, @Nullable AttributeSet attrs, int defStyleAttr)
View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes)
기본 속성값, 기본 리소스 값도 생성자로 주입할 수 있다.
Attachment/ Detachment
window 에 attach 되었는지 detach 되었는지를 의미한다
- onAttachedToWindow() : 이때부터 View 가 Active 하다. 따라서 Resource 나 Listener 를 할당할 수 있다.
- onDetachedFromWindow() : 더 이상 View 가 Active 하지 않다. 따라서 할당된 리소스를 해제해줘야 한다. ViewGroup 에서 View 가 지워질 때, 혹은 액티비티의 finish() 가 호출되었을 때 등의 상황에서 호출된다.
onMeasure()
View 의 크기를 재는 단계이다. ViewGroup 은 하위 노드의 View 크기를 먼저 측정하고 그에 따라 자신의 크기를 결정한다.
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
- MeasureSpec
뷰의 크기를 측정할 때 부모 뷰에서 자식 뷰로 전달되는 요구사항이다.
MeasureSpec.EXACTLY : 자식 뷰의 크기와 상관없이 부모 뷰가 자식 뷰의 정확한 크기를 결정한다.
MeasureSpec.AT_MOST : 자식 뷰는 지정된 크기 안에서 원하는 만큼 커질 수 있다.
MeasureSpec.UNSPECIFIED : 부모 뷰가 자식 뷰에 제한을 두지 않는다. 원하는 만큼 커질 수 있다.
onLayout()
크기 측정을 완료했다면 View 를 Window 에 배치한다.
protected void onLayout(boolean changed, int left, int top, int right, int bottom)
onDraw()
크기 계산 및 배치를 완료했다면 이를 기반으로 그려야한다. Canvas 객체를 GPU 에게 전달한다. onDraw() 는 한 프레임을 그리는 함수로 여러 번 호출될 수 있기 때문에 무거운 작업을 하지 않아야한다. 객체를 만들어서 사용한는 것은 금기시한다.
invalidate() vs requestLayout()
뷰의 변화를 시스템에게 알린다.
- invalidate() : view 의 속성이나 데이터(모양)이 변했을 때 사용한다. draw 과정이 수행된다.
- requestLayout() : view 의 경계에 변화가 생겼을 때 사용한다. measure -> layout -> draw 단계를 다시 거친다.
이 두 가지 함수는 반드시 UI thread 에서 호출해야 한다!
만약 다른 스레드에서 업데이트 시키고 싶다면 handler 를 이용하자~
뷰 최적화 방법
<참고>
https://developer.android.com/training/custom-views/optimizing-view?hl=ko
1. ConstraintLayout 을 사용하면 뷰 계층을 단순화 할 수 있어 계층 구조 순회 비용을 줄일 수 있다! 또한 장풍 구조를 단순화하자
2. RecyclerView 의 setHasFixedSize 를 false 로 설정하면 requestLayout() 을 호출한다.
안드로이스 UI 시스템은 뷰의 크기가 얼마나 되는지 알아내기 위해 매번 뷰 계층 구조를 순회해야한다.
이는 비용이 비싸다. 따라서 RecyclerView 의 item 이 변하지 않는다면 setHasFixedSize 를 true 로 변경해주자!
3. 복잡한 UI 라면 custom ViewGroup 사용을 고려해보자. 애플리케이션 별로 하위 요소의 크기 및 모양을 추정할 수 있어 순회하지 않아도 된다.
'Android' 카테고리의 다른 글
RecyclerView 목록 스크롤에 CoordinatorLayout 적용하기 (0) | 2023.11.17 |
---|---|
[안드로이드] Repository Pattern (저장소 패턴) (0) | 2023.10.26 |
[안드로이드] LiveData 를 Flow 로 Refactoring 하기 (0) | 2023.09.20 |
Reflection [우아한테크코스 5기 AN_베르] (0) | 2023.09.10 |
[안드로이드] 테스트 라이브러리 Robolectric (0) | 2023.09.03 |