[Android] 레이아웃 계층 성능 최적화(Optimizing Layout Hierarchies)

[Android] 레이아웃 계층 성능 최적화(Optimizing Layout Hierarchies)


원문: Optimizing Layout Hierarchies을 번역한 글입니다.

베이직 레이아웃 구조를 사용하는 것이 가장 효과적인 레이아웃이 된다는 것은 흔한 오해입니다. 그러나, 당신이 애플리케이션에 추가한 각 위젯과 레이아웃은 초기화, 배치, 그려지는 과정이 필요합니다. 예를 들어, 중첩된 LinearLayout을 사용하는 것은 지나치게 깊은 뷰 계층을 초래할 수도 있습니다. 게다가, layout_weight를 사용하는 몇 개의 LinearLayout을 중첩하는 것은 각 child가 한번 더 측정되기 때문에 특히 비용이 높습니다. ListViewGridView를 사용할 때처럼 inflate가 반복되는 경우 특히 중요합니다.

이 글을 통해 레이아웃을 검토하고 최적화하기 위한 Hierarchy ViewerLint 사용법을 배울 수 있습니다.

레이아웃 검토하기

Android SDK tools에는 애플리케이션 실행 동안 레이아웃을 분석할 수 있게 해주는 Hierarchy Viewer가 포함되어 있습니다. 이 툴을 이용하여 레이아웃 성능측면에서의 병목현상(bottleneck)을 발견할 수 있습니다.

Hierarchy Viewer는 실행중인 연결된 기기나 에뮬레이터 선택함으로써 동작하고, 레이아웃 트리를 보여줍니다. 각 블록은 Measure / Layout / Draw 성능을 나타내며, 이를 통해 잠재적인 이슈를 파악할 수 있습니다.

예시를 보면, figure 1은 ListView의 item으로 쓰인 레이아웃 하나를 보여줍니다. 이 레이아웃은 왼쪽에 작은 비트맵 하나와 오른쪽에 두 개로 쌓인 텍스트 아이템으로 구성됩니다. 이 레이아웃처럼 여러번 inflate될 레이아웃이 최적화하는 것은 성능 이득을 배로 늘릴 수 있기 때문에 특히 중요합니다.

Figure 1. ListView의 아이템에 대한 개념적인 레이아웃 예시.

Hierarchy Viewer는 가능한 디바이스와 그들의 실행중인 컴포넌트 리스트를 보여줍니다. Windows 탭에서 컴포넌트를 선택하세요. 그리고 Hierarchy View를 클릭하면 선택한 컴포넌트의 레이아웃 계층 구조를 볼 수 있습니다. 예를 들어, figure 2는 figure 1의 레이아웃을 보여줍니다.

Figure 2. 중첩된 LinearLayout을 사용한 figure 1의 레이아웃 계층 구조

레이아웃 개선하기

위 예시의 레이아웃 성능은 중첩된 LinearLayout으로 인해 느리기 때문에, 레이아웃의 중첩을 줄여(flattening;평평하게 하다) 성능을 향상시킬 수 있습니다ㅡ레이아웃을 좁고 깊게 만들기보다, 얕고 넓게 만드세요. Root 노드로서 RelativeLayout은 그런 레이아웃을 가능하게 합니다. 그럼 이 디자인을 RelativeLayout을 사용하는 방법으로 전환했을 때, 레이아웃이 2-level 계층으로 바뀌는 것을 알 수 있습니다. 새로운 레이아웃의 결과는 이렇게:

Figure 3. RelativeLayout을 이용한 figure 1의 레이아웃 계층 구조

이 레이아웃은 목록의 모든 항목에 사용되기 때문에 위에 보이는 것처럼 작은 이점이 몇 배가 될 것입니다.

가장 큰 차이점은 LinearLayout 설계에서 layout_weight 사용은 측정 속도를 느리게 할 수 있다는 점입니다. 이건 각 레이아웃을 얼마나 적절히 사용하는지에 대한 한 가지 예시이고, 우리는 layout weight를 사용하는 것이 정말 필수적인지 신중하게 고려해야 합니다.

몇몇 복잡한 레이아웃의 경우, 시스템이 같은 UI 요소를 중복으로 측정하느라 성능을 낭비할 수도 있습니다. 이 현상을 double taxation이라고 부릅니다. double taxation에 대한 더 많은 정보와 이를 어떻게 방지하는지는 Performance and View Hierarchies를 참고하세요.

Lint 사용

가능한 뷰 계층 최적화를 찾기 위해 레이아웃 파일에 대해 lint tool을 실행하는 것은 항상 좋은 습관입니다. Lint는 Layoutopt tool을 대체했고, 더 좋은 기능성을 갖추고 있습니다. lint 에 대한 몇 개의 예시입니다: Compound Drawable을 사용하세요 - 하나의 ImageView와 하나의 TextView를 갖는 LinearLayout은 한 compound drawable로 다루면 더욱 효율적일 것입니다.

  • root 프레임을 합치세요 - 만약 레이아웃의 root가 FrameLayout이고 background나 padding 등을 주지 않았다면, 조금 더 효율적인 merge 태그로 대체될 수 있습니다.
  • 사용하지 않는 leaf - 자식이 없거나 background가 없는 레이아웃은 중첩을 없애고 더 효율적인 레이아웃 계층 구조를 위해서 거의 삭제 가능합니다.(안 보이기 때문에)
  • 사용하지 않는 부모 - background가 따로 없고, ScrollView나 루트 레이아웃이 아닌데도 자식 뷰 하나를 갖는 레이아웃은 중첩 제거와 효율적인 레이아웃 계층을 위해 삭제 가능하고 그 자식 뷰를 부모 뷰로 바로 옮겨도 됩니다.
  • 깊은 레이아웃들 - 너무 많이 중첩된 레이아웃은 성능상 좋지 않습니다. 성능 향상을 위해 RelativeLayout이나 GridLayout같은 중첩이 많이 필요없는 레이아웃을 고려해보세요. depth의 기본 최대치는 10입니다.


Lint의 또 다른 장점은 Android Studio에 통합되어 있다는 점입니다. Lint는 여러분이 프로그램을 컴파일할 때마다 자동으로 실행됩니다. Android Studio를 쓴다면, 여러분은 또한 특정 빌드 타입 또는 모든 빌드 타입에 대해 lint 검사를 실행할 수 있습니다.

그리고 Android Studio의 File>Settings>Project Settings 옵션에서 검사의 profile과 속성을 관리할 수 있습니다. 지원되는 검사와 함께 inspection configuration 페이지를 볼 수 있습니다.


Figure 4. Inspection Configuration



Comments