ConstraintLayout ?
2016년 Google IO 에 공개된 레이아웃 에디터에 상호연관 시키기 위해 도입된 Layout 이다.
'constraint' 라는 단어 의미대로 제약조건을 걸어 View 들을 배치하는 역할을 하는 Layout 이다.
정말 다양한 제약조건이 있다. 이 부분은 android developer 를 참고하여 자세히 알아보자.
왜 ConstraintLayout 을 사용하라고 할까?
뷰 Layout 작업을 할 때 컨스트레인트 레이아웃을 주로 사용하라는 다른 글을 많이 보았다.
퍼포먼스 측면에서 좋다는 글을 봐서 개발할 때 늘 그렇게 개발했다.
하지만 여기서 그 왜? 라는 의문을 갖고 글을 적어보려한다.
그 이전에 우리는 개발자로써 Layout 작업을 하기 이전에 Rendering Process 를 알고있어야 한다.
Rendering Process 를 알고 있어야, 그 왜 라는 질문에 답을 이해할 수 있다.
다시 돌아가서, 왜 컨스트레인트 레이아웃을 사용하라고 할까?
두 가지로 크게 나누어 설명할 수 있을 것이다.
1. 복잡성 관리 (Manage complxity): 레이아웃의 중요성
흔히 뷰 계층 구조가 평평할수록 레이아웃 단계를 완료하는 데 드는 시간이 줄어든다는 것을 알 것이다.
그 이유는 뷰 객체의 계층구조가 서로 중첩되어 있을 경우 중첩된 각 레이아웃 객체는 비용이 추가된다.
이러한 중첩이 왜 비용이 추가되는 이유는 레이아웃 객체를 처리할 때 앱은 레이아웃의 모든 하위 요소(view) 에서도 동일한 프로세스를 실행하기 때문이다.
예시로,
RelativeLayout 클래스를 사용하고 있다면, LinearLayout 뷰를 대신 사용하여 더 낮은 비용으로 동일한 효과를 달성할 수 있다.
또한
Layout Editor 를 사용하여 ConstraintLayout 객체를 만든다면, RelativeLayout 이 갖는 중첩되는 상황을 평평한 뷰 구조로 만들 수 있게 레이아웃 컨트롤을 할 수 있다.
복잡한 레이아웃(뷰 트리구조)를 제약조건으로 뷰 사이 관계를 해결하기 때문에 컨스트레인트 레이아웃 사용을 권장한다.
2. 이중과세 (Double taxation)
일반적으로는 레이아웃과 측정 단계를 단일 관계로 매우 빠르게 실행된다.
하지만, 일부 복잡한 레이아웃인 경우 요소(view) 를 배치하기 전에 여러 번 반복해야 해결할 수 있는게 계층 구조다.
여기서 레이아웃 및 측정 반복을 두 번 이상 실행해야 하는 것을 이중과세라고 한다.
이중과세를 이해하기 위해 RelativeLayout 을 예시로 들어보자.
A(View) 객체의 위치를 기준으로 B(View) 객체를 배치 할 수 있는 RelativeLayout 을 사용하는 경우,
첫 번째 : 각 하위 개체의 위치와 크기를 각 하위 개체의 요청에 따라 계산하는 레이아웃 과 측정 단계를 실행한다.
두 번째 : 해당 정보를 사용하여 개체 가중치를 고려하여 연관되 뷰의 적절한 위치를 파악한다.
세 번째 : Rendering Process 의 두 번째인 레이아웃 단계를 수행하여 개체의 위치를 완성 시킨다.
마지막 : 렌더링을 처리해야할 곳으로 이동한다.
이렇게 되면, 뷰 계층의 깊이(depth) 가 깊을수록 잠재적인 성능 저하가 커지게된다.
이처럼 RelativeLayout 이외의 다른 레이아웃 또한 이중 과세를 발생시킬 수 있다.
Other Layout case
- LinearLayout : 뷰를 Horizontal 로 만들게되면, 이중으로 layout-measure 단계가 발생할 수 있다. 또한 measureWithLaigestChild 를 추가하는 경우에도 이중으로 layout-measure 단계가 수직 방향으로 발생할 수 있다.
- GridLayout : 해당 레이아웃은 상대적 위치 지정도 허용하지만, 일반적으로 View 간의 위치 관계를 전처리하여 이중과세를 방지한다. 하지만, 레이아웃이 가중치를 사용하거나, gravity 로 채우면 해당 전처리의 이점이 손실되고 컨테이너가 RelativeLayout 인 경우 이중 과세 단계를 수행해야 할 수 있다.
- FrameLayout : 자식을 하나만 갖도록 설계 되었다. overlay UI 를 만드는데 도움이되는 하위 항목을 하나씩 쌓게된다. 또한 사용자 정의 뷰의 경우 상위 뷰에 매우 적합한 옵션이다. 하지만, 해당 레이아웃은 부모에 상대적인 gravitiy 옵션을 적용해야만 하위 뷰를 배치할 수 있다.
위와 같이 다른 레이아웃을 컨스트레인트 레이아웃과 비교를하였다.
컨스트레인트는 LinearLayout(가중치 설정) 과 RelativeLayout(상대위치설정) 의 이점을 모두 갖고 있다.
하지만, 간단한 UI 에 굳이 사용할 필요는 없을 것이다.
성능 측면에서도 ConstraintLayout 이 다른 Layout 보다도 좋은 것일까? (블로그 참고)
1. 다른 뷰 중앙에 새로운 뷰를 배치하는 경우? : FrameLayout > ConstraintLayout > LinearLayout
좋다고 했던 ConstraintLayout 은 1depth 인 경우, FrameLayout 보단 성능이 떨어진다.
2. 100개의 아이템을 가진 RecyclerView 가 있을 경우? : ConstraintLayout > LelativeLayout > LinearLayout
LinearLayout 가 가장 성능이 좋지 않다. 하지만, RecyclerView 는 ConstraintLayout 안에서 RelativeLayout 보다도 좋은 성능을 보여준다.
3. TextView 와 ImageView 로만 이루어진 간단한 UI인 경우? : LinearLayout > ConstraintLayout
간단한 경우, LinearLayout 이 성능이 좋다.
1번 case 와 같이 1depth 에 자식 뷰의 위치 및 크기를 구해야 하는 경우가 아니라면, 굳이 ConstraintLayout 을 사용할 필요는 없다.
4. ScrollView & ImageView & TextView, Button 등으로 이루어진 좀 더 복잡한 UI인 경우? : ConstraintLayout > Other Layout
3번 case 와 다르게 복잡하게 이루어진 UI 라면? ConstraintLayout 이 큰 이점을 갖는다.
위에서 설명한대로 정말 맞는지 테스트 기반으로 성능을 비교한다면 과연 그럴까?
1. 하나의 레이아웃 안에 3개의 텍스트 뷰가 있는 경우? : LinearLayout > ConstraintLayout
2. 다른 뷰 중앙에 새로운 뷰(Progress Bar)를 배치하는 경우? : FrameLayout > LinearLayout > ConstraintLayout
3. 레이아웃 내 양 끝(가중치 사용)에 뷰를 배치하는 경우? : LinearLayout > RelativeLayout > ConstraintLayout
ConstraintLayout 은 Linear 의 가중치 장점을 갖는다고 했다. 그래서 성능 결과는 미비하다. 하지만, 역시나 Linear 가 우세하다.
4. ScrollView & ImageView & TextView, Button 인 경우? : LinearLayout > ConstraintLayout
위에서 다른 레이아웃을 비교했을 때, 복잡하게 이루어지 UI 일 경우, ConstraintLayout 이 빠르다고 했었다. 하지만, 테스트 결과 그렇지 않았다.
정리
렌더링 성능 때문에 평탄한 뷰를 가진 ConstraintLayout 이 다른 뷰에 비해서 이점을 갖는다 했다.
하지만, 테스트를 확인했을 때 그렇지 않은 상황들도 많았다.
모든 기술이 그렇듯 단정지어 이분법 사고로 무엇이 좋다라고 말할 수 없다.
물론, RecyclerView 를 사용하는 경우에는 ConstraintLayout 이 갖는 이점이 크다는 건 확인 됐다.
우리가 레이아웃 구조를 잡을 때, 계층화를 평탄화 시키는 것도 중요하지만, XML 파일 내 코드 가독성도 중요하다. 그러니, 트레이드오프를 생각하며 레이아웃 구조를 잡으면 좋을 것 같다.
추가
레이아웃 렌더링 하는 과정 성능 테스트에 대해서...
인간의 뇌는 눈으로 보는 시각적인 정보를 지속적으로 수신하고 처리를 한다.
스틸이미지(움직이는 사진) 라고 알 것이다. 흔히 플립북을 생각하면 된다. 이러한 스틸 이미지는 마치 모션으로 우리는 인식을 한다.
여기서 새로운 개념인 1프레임의 시간이라는 것을 기억해보자.
1프레임의 시간
플립북 기준으로 생각을 해보자.
- 초당 약 10-12페이지 이동 : 이동속도는 분명하지만, 개별 페이지에 대한 인식도 유지하게된다.
- 초당 24페이지 : 페이지를 통해 애니메이션의 각 프레임만 볼 때 움직임을 인식하는데 도움이되는 모션 흐림과 같은 기술 덕분에 사람의 눈은 스틸이미지를 더욱 유동적인 움직임을 볼 수 있게 됐다. 저렴한 예산으로 영화를 제작할 정도의 빠른 움직임이다.
- 초당 30페이지 : 굉장히 빠르지만, 실제와 같지는 않다.
- 초당 60페이지 : 대부분의 사람들이 고품질의 부드러운 모션으로 보기에 이상적이다.
android developer 에서도 앱이 원활하게 작동하도록 하려면, 60fps(16ms/프레임)를 타겟팅하는 것이 좋다고 나와있다.
앱이 필수 프레임 렌더링 시간을 충족하지 않으면 시스템은 프레임을 강제로 건너뛰고 사용자는 이를 앱 끊김 현상으로 인식하게 된다.
화면 프레임 누락으로 인한 이러한 매끄럽지 않은 상호작용을 버벅거림이라고 한다.
성능 테스트 방법
- GPU Overdraw : 휴대폰 설정에 '디버그 GPU 오버드로' 에서 오버드로 영역표시를 선택하여 앱 오버드로를 감지하여 확인하면서 오버드로 방지를 할 수 있다.
- Systrace : 이 도구는 앱의 프로세스 및 Android 시스템 프로세스의 실행 시간을 캡처 후, 표시하여 앱 성능 분석하는데 도움을 준다.
참고한 블로그
https://www.organimi.com/what-is-a-hierarchy-diagram/
https://developer.android.com/topic/performance/rendering/optimizing-view-hierarchies?hl=ko
https://developer.android.com/topic/performance/vitals/tracking_jank?hl=ko
https://medium.com/android-news/constraint-layout-performance-870e5f238100
'Mobile App' 카테고리의 다른 글
[안드로이드] - 클린아키텍처 - 0 (0) | 2023.01.27 |
---|---|
[안드로이드] - ShardPreferences, Datastore 차이 (0) | 2023.01.27 |
[안드로이드] - Flow (coroutine) - 0 (0) | 2023.01.18 |
[안드로이드] - coroutine (코루틴) - 0 (1) | 2023.01.18 |
[안드로이드] - coroutine (코루틴) - 1 (0) | 2023.01.18 |