Android RelativeLayout 는 많은 비용을 소비하는가?

본 글은 본인의 Medium 에서 가져왔음을 밝힙니다.

이 글은 Android RelativeLayout에 대한 작은 고찰 에서 이어집니다.

해당 글을 올린 이후 약 4개월 뒤인 10월 말, Palette 1.0과 2.0의 레이아웃 측정 속도를 직접 비교할 수 있는 기회가 생겼습니다.

테스트 조건

  • Galaxy S6 실제 사용 기기
  • 사용된 계정: @WindSekirun
  • 조건: 주황색 + 어두운 색 배경, systrace 를 수집하는 10초 동안 계속 아래로 스크롤
  • 분석에 사용된 툴은 Systrace 라는 툴로, 안드로이드 SDK에서 기본 제공되고 있습니다.

주요 비교 이미지, 오른쪽이 1.0, 왼쪽이 2.0 입니다.

설명

Systrace 에서는 UI 스레드에서 해당 작업이 걸린 시간등을 분석하여 보여주는 역할을 합니다.

  • Scheduling delay: 다른 스레드에서 작업하는 동안 대기 시간
  • Path texture charn: 그래픽 텍스쳐를 기다리는 시간
  • Long View#draw(): 실제 뷰를 그리는 시간
  • Expensive measure/layout pass: RelativeLayout 가 레이아웃을 구성하는 데 걸리는 시간

이 중, 주로 UI 의 속도를 측정할 수 있는 기준은 ‘Expensive measure / layout pass’ 입니다.

  • Timespent — RelativeLayout 에 있는 childView 들이 표시되기 위해 소요되는 시간
  • measure — 변경된 뷰 크기 계산 시간
  • Layout — 변경된 뷰의 크기나 위치에 따라 실제로 레이아웃을 구성하는 시간

즉, 위 사진을 정리하면 아래와 같은 결과를 도출하였습니다.

 

안드로이드 앱 UI 을 만들 때, 가장 자유롭게 만들 수 있게 하는 레이아웃은 RelativeLayout 입니다. 해당 위젯의 이름대로 Relative, 상대적으로 설정할 수 있어 디자이너가 ‘이거 5dip만’ ‘이거 1dip만’ 옮겨달라고 할 때 쉽게 대응이 가능합니다.

하지만, RelativeLayout는 속한 레이아웃(Child)가 많으면 많을 수록 차일드 뷰의 위치나 크기를 계산하는 데에 많은 시간을 소요하게 됩니다. (당장 Palette 2.0만 해도 약 15개의 Child View를 가지고 있습니다.)

그래서 최근 글의 제목처럼 ‘과연 복잡한 레이아웃을 사용하려고 할 때, RelativeLayout는 많은 비용을 소비하는가?’ 라는 논란이 일어나고 있고, 이에 대응하기 위하여 다른 레이아웃을 이용하기도 합니다. (물론, 디자이너가 개발자한테 ‘디자이너님 이거 구성하려면 할 수는 있는데 이런 문제들이 있어요’ 라고 들었을 때 순순히 요청을 들어줄지는… (._.

결국 이런 문제는 UI를 디자인하는 디자이너와 기획자, 그리고 개발자간 협의가 필요합니다. 간단한 앱이라면 상대적으로 상관이 없지만, 무거운 앱이거나 실시간으로 올라오는 내용이 많은 앱의 경우 이러한 곳에서 발생하는 딜레이 하나하나가 최종적으론 앱 품질에 영향을 끼치기 때문입니다.

결론

  • 간단한 앱이거나, ListView를 사용하지 않거나 ListView를 표시하더라도 보여주는 뷰 갯수가 적다 -> 영향을 거의 미치지 않습니다.
  • 소셜 네트워크 앱 등 실시간으로 계속 갱신되야 하거나, 사진이 많이 올라온다 -> 영향을 매우 많이 미칩니다. 이 경우 개발자가 어느정도 신경을 써야 합니다.

물론, RecyclerView Prefetch 나 ViewHolder Pattern, Image Loader Library (Glide, Picasso, Fresco) 등을 이용하면 대부분의 렉을 최소화할 수 있지만 만약 개발하는 앱이 이런 것 들을 전부 적용했는데도 렉이 걸린다면 뷰 쪽을 살펴보는 것도 좋을 것 같습니다.

Android RelativeLayout에 대한 작은 고찰

본 글은 본인의 Medium 에서 가져왔음을 밝힙니다.

누구나 한번 안드로이드 애플리케이션을 개발하다보면, RelativeLayout 를 한번이라도 사용해보았을 것이다. LinearLayout 와 비교해서 자유로운 뷰 구성이 가능하1고, 디자이너들이 1dip 만 옮겨달라고 하는 등 빛을 발휘하는 것이 RelativeLayout다.

최근에 본인은 안드로이드 소셜 네트워크 앱을 개발하면서 당연하게도 이 RelativeLayout를 자주 쓸 수 밖에 없었고, 이에 거의 모든 앱 화면 구성을 RelativeLayout로만 구성하게 되었다. (물론, 이때까지 이런 레이아웃이 성능에 영향을 미치리라는 조금도 예상하지 못했다.

모 안드로이드 소셜 네트워크 앱의 레이아웃 구조, 파란 테두리의 사각형이 하나의 RelativeLayout로 본다. (물론, 최근 개발하는 버전에서는 저 파란 테두리 사각형이 70% 이상 줄었다.)

안드로이드의 RelativeLayout는 뷰에 렌더링될 때 아래와 같은 과정을 거친다.

  1. RelativeLayout 안에 있는 위젯들이 원하는 위치에 갈 수 있도록 위치와 크기를 계산한다.
  2. RelativeLayout 는 1에서 얻은 데이터를 활용하여 연관된 뷰의 위치나 상대적인 사이즈를 계산하고 그에 맞춰 경계선을 조절한다.
  3. 이 상태에서 두번째 레이아웃 패스에서 계산이 일어나, 렌더링(표시)에 쓸 최종 위치를 계산한다.

해당 내용은 Android Performance Pattern 의 Double Layout taxation의 1분 20초부터 볼 수 있다. (한글CC가 된다)

결국, 한 번의 레이아웃을 렌더링 할 때 두 번의 레이아웃 패스 계산이 일어난다. 더 중요한 것은, 이 작업은 RelativeLayout가 갱신될 때마다 일어난다.

즉 결론이 무엇이냐. 하면, RelativeLayout와 연관된 뷰가 많을 수록, 렌더링 할 때의 시간이 기하급수적으로 늘어난다. 만약, 뷰 그리는 시간에 너무 많은 시간을 소요한다면 나머지 작업을 할 시간도 당연하게도 없어지겠고, 결국Lack로 이어진다고 볼 수 있다.

이를 해결하기 위한 방법은, 안타깝게도 한가지 밖에 존재하지 않는다. RelativeLayout를 남용하지 않는 것이다. 물론, RelativeLayout의 사용을 줄이게 되면 앱 디자인에 제약이 생길 수가 없고, 이는 디자이너가 원망의 눈빛으로 당신을 바라보게 될지도 모르겠다(.)

물론, 이 문제는 ‘소수의 앱’만 속하는 문제기도 하다. 하지만, 왠만한 방면에서 최적화를 했는데도 렉이 걸린다면, 레이아웃 xml를 다시 돌아보는게 좋다고 생각된다. (안드로이드가 최근 60FPS 강조하는 것도 있고. 이에 관해선 또 다른 글에서.)

      1. 앱 빌드를 기다리는 동안.