로드 지연 원인으로 추측되는 뷰 그룹
주석 부분에서 레이아웃을 로드할 때 지연이 발생하는 원인이라고 가정해보겠습니다.<!-- layout_main.xml -->
<ViewGroup>
<View>
<!-- ViewStub 적용 시작 -->
<ViewGroup>
<View>
<View>
</ViewGroup>
<!-- ViewStub 적용 끝 -->
<View>
<ViewGroup>
layout_main.xml
레이아웃에서 ViewStub
을 적용하기 위해서는 적용 대상이 되는 부분을 별도의 레이아웃 xml 파일로 분리해 줍니다.ViewStub
을 추가하고, 아래 속성을 반드시 지정해주어야 합니다.<!-- 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>
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) {
}
}
내부에
LayoutInflater
와WeakReference<View>
를 필드로 가지고 있습니다.
View inflate()
혹은void setVisibility(int)
를 호출하면
ViewStub
내부에서getParent()
를 호출해 부모 뷰를 찾아ViewGroup
인지 확인한다.- 그리고 xml에서 정의된
android:layout
필드를 인플레이트 하여 View를 생성한다.ViewStub
이 있는 위치를 찾아 스스로를 부모 뷰에서 지우고,
(2)에서 생성된View
를 추가한다.
대략적인 절차를 보면 이렇습니다. 그래서 inflate()
를 호출하기 전에는 뷰가 로드가 되지 않고, 크기가 0인 뷰로 위치하고 있는 것입니다.
한 번에 로드하면 로딩 지연(뜨는데 시간이 걸리는 상황)이 발생하는 뷰를 초기화되는 시점을 잘 분석해서 로드되는 시점을 분리하면 성능을 개선할 수 있습니다.
예를 들면,3개 로드하는데 2초가 걸리는 레이아웃이 있다고 하면, 레이아웃을 업데이트 하는 API가 있다면 응답이 오는 시점에 ViewStub
을 통해 지연 로드하면 활용할 수 있습니다.