[Android] xml 레이아웃 지연 로딩

김개발소발·2021년 6월 1일
0

android

목록 보기
1/1
post-thumbnail

ViewStub?

  • 레이아웃을 로딩하는 과정에서 복잡한 레이아웃이 로딩 지연이 발생하는 경우가 있습니다.
  • 다양한 상세화면 이나 언제 사용될지 모르는 레이아웃 등 필요한 시점에
  • 레이아웃을 로드 가능한 크기도 없고, 가벼우며, 어떤 draw 작업도 없는 뷰View 입니다.

어떻게 하면 되나요?

  1. 간단한 예를 들어 복잡하지 않지만, 아래와 같은 구조의 레이아웃이 있다고 가정하겠습니다.
    그리고 중간에 주석으로 로드 지연 원인으로 추측되는 뷰 그룹 주석 부분에서 레이아웃을 로드할 때 지연이 발생하는 원인이라고 가정해보겠습니다.
<!-- layout_main.xml -->

<ViewGroup>
	<View>
		
          <!-- ViewStub 적용 시작 -->
          <ViewGroup>
          	  <View>
              <View>
          </ViewGroup>
          <!-- ViewStub 적용 끝 -->
                
	<View>
<ViewGroup>

  1. layout_main.xml 레이아웃에서 ViewStub을 적용하기 위해서는 적용 대상이 되는 부분을 별도의 레이아웃 xml 파일로 분리해 줍니다.
    그리고 ViewStub을 추가하고, 아래 속성을 반드시 지정해주어야 합니다.
  • id
  • layout
<!-- layout_sub.xml -->

<ViewGroup>
    <View>
	<View>
</ViewGroup>

그럼 layout_main.xml은 다음과 같은 모양이 됩니다.

<!-- layout_main.xml -->
<ViewGroup>
	<View>
      
    	<!-- 로딩 지연 유발 지점으로 지연 로드 적용하기 위해 떼어낸 부분 -->
      	<ViewStub
      	android:id="@+id/view_stub_id"
        android:layout="@layout/layout_sub.xml"/>
      
	<View>
<ViewGroup>

  1. 다음 ViewStub으로 지연 로드를 적용할 레이아웃을 필요한 시점에 코드에서 로드합니다.
// MainActivity.java
public class MainActivity extends AppCompatActivity {
	
    	private ViewStub subLayoutViewStub;
    
    
	public void onCreate(Bundle savedInstance){
		subLayoutViewStub = findViewById(R.id.view_stub_id);
	}
    
    private void layoutSubLayout() {
    	View view = subLayoutViewStub.inflate();
        // ViewStub 하위 뷰 바인딩
        // view.findViewById~~
    }
}

이렇게 ViewStub.inflate() 혹은 setVisibility(View.VISIBLE)을 호출하는 시점에 뷰가 로드됩니다.

그럼 어떤 절차로 지연 로드가 되나요?

크기도 없고, 가벼우며, 어떤 draw 작업도 없는 뷰View

이번 글의 가장 처음 ViewStub을 소개했습니다.
draw 작업이 없으니 크기도 없고, 크기가 없으니 가벼운 View가 될 수 밖에 없습니다.

public final class ViewStub extends View {
	
    /*
    View를 상속받지만,
    draw(Cavas)에서는 뷰를 그리기 위한 어떤 작업도 없습니다.
    */
    @Override
    public void draw(Canvas canvas) {
    }

}

내부에 LayoutInflaterWeakReference<View>를 필드로 가지고 있습니다.
View inflate() 혹은 void setVisibility(int)를 호출하면

  1. ViewStub 내부에서 getParent()를 호출해 부모 뷰를 찾아 ViewGroup인지 확인한다.
  2. 그리고 xml에서 정의된 android:layout 필드를 인플레이트 하여 View를 생성한다.
  3. ViewStub이 있는 위치를 찾아 스스로를 부모 뷰에서 지우고,
    (2)에서 생성된 View를 추가한다.

대략적인 절차를 보면 이렇습니다. 그래서 inflate()를 호출하기 전에는 뷰가 로드가 되지 않고, 크기가 0인 뷰로 위치하고 있는 것입니다.

음...

한 번에 로드하면 로딩 지연(뜨는데 시간이 걸리는 상황)이 발생하는 뷰를 초기화되는 시점을 잘 분석해서 로드되는 시점을 분리하면 성능을 개선할 수 있습니다.

예를 들면,3개 로드하는데 2초가 걸리는 레이아웃이 있다고 하면, 레이아웃을 업데이트 하는 API가 있다면 응답이 오는 시점에 ViewStub을 통해 지연 로드하면 활용할 수 있습니다.

profile
사람들 속에 숨어사는 INTJ 성향을 가진 개발자

0개의 댓글