본문 바로가기
개발/안드로이드

안드로이드 include, merge, viewstub

by 창이2 2021. 7. 8.

안녕하세요.

이번 포스팅에서는 안드로이드에서 뷰의 성능 개선을 위한 

3가지 태그를 설명 드리려고 합니다.

 

우리가 일반적으로 xml에 레이아웃을 정의하면 

똑같은 뷰를 여러번 정의하거나 쓸까 말까한 뷰도 생성되게 정의하거나

또는 레이아웃의 깊이가 깊어져 성능이 안좋아 지는 경우가 있습니다.

 

이를 개선하기 위해 사용되는 것이 위 3개의 태그입니다.

 

첫째로 같은 레이아웃을 여러번 그릴 때 <include> 태그로 이를 개선할 수 있습니다.

<include> 를 사용하면 하나의 레이아웃을 정의함으로써 동일한 레이아웃을 여러번 

정의할 수 있기 때문에 굉장히 편리한 태그입니다.

 

우선 include할 layout 파일을 만든 후 이를 <include>으로 감싼다음

android:layout = "@layout/include_appbar" 를 정의하여 사용할 수 있습니다.

또한 데이터바인딩을 이용하여 includ_appbar의 변수에 접근할 수 있습니다.

    <include layout="@layout/include_appbar"
    	android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

 

 

두번째로 뷰의 깊이를 줄이기 위해 사용되는 <merge> 태그입니다.

만약 뷰를 배치하는데 불필요하게 레이아웃이 중첩되면(리니어 안에 또 다른 리니어) 뷰를 그리는데

성능만 떨어지게 됩니다.

이 때 <merge>태그를 사용하면 중복되는 레이아웃 없이 그릴 수 있게 됩니다.

 

<merge xmlns:tools="http://schemas.android.com/tools">
    <TextView
        android:id="@+id/header"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:background="@color/purple_200" />

    <TextView
        android:id="@+id/body"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:background="@color/purple_200"/>
</merge>

이렇게 <merge> 태그로 감싼 후 

        <include layout="@layout/merge_text"/>

<include>로 감싸 호출하시면 됩니다.

 

다만 주의해야할 점은 ConstraintLayout에서 사용할 때 <include>태그안의 Constraint조건들이 무시되기 때문에

적절한 상황에서 사용하시면 될거 같습니다. 

또한 <merge> 태그 안에 아이디를 통한 바인딩이 안되기 때문에 이 또한 주의하셔야 할거 같습니다.

(예를 들면 binding.merge_text.aaa 가 안됨)

 

 

세번째로 뷰를 쓰일지 안쓰일지 모르는 상황일 때 필요한 상황에서 inflate()하기 위한 <viewstub> 태그가 있습니다.

뷰를 필요한 시점에 로드하기 때문에 안쓰이는 상황에서 효율적으로 활용할 수 있습니다.

일단 아래 처럼 새로운 레이아웃을 생성해 줍니다. 

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android">

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="50dp"
    android:layout_height="50dp">
    <ProgressBar
        android:id="@+id/progressBar"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

그리고 쓰이는 곳에서 <viewstub>코드로 감싸 사용하시면 됩니다.

 

    <ViewStub
        android:id="@+id/progressViewStub"
        android:layout="@layout/viewstub_progress"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>

그리고 클래스 파일에서

            val progressViewStub =  binding.progressViewStub
            if(!progressViewStub.isInflated){
                val view: View? = progressViewStub.viewStub?.inflate()
            }

이렇게 인플레이션 해주면 된다.

viewStub에서 데이터바인딩을 할 때 불편한점이 있다.

viewStub이 inflate() 호출 후 그에 대한 바인딩을 수행하는 리스너를 달아야 한다는 점이 있다.

            var stubBinding: ViewstubProgressBinding? = null
            progressViewStub.setOnInflateListener { stub, inflated ->
                stubBinding = ViewstubProgressBinding.bind(inflated)
            }

 

위 코드들은 아래 깃허브에서 확인하실 수 있습니다.

 

https://github.com/ckdrb7017/BlogProject/tree/master/ViewReusing

 

ckdrb7017/BlogProject

개인 블로그 프로젝트를 올리는 곳입니다. Contribute to ckdrb7017/BlogProject development by creating an account on GitHub.

github.com

 

 

https://developer.android.com/training/improving-layouts/loading-ondemand?hl=ko 

 

뷰 로드 지연  |  Android 개발자  |  Android Developers

때때로 레이아웃에 거의 사용되지 않지만 복잡한 보기가 필요한 때가 있습니다. 보기의 종류(예: 항목 세부정보, 진행률 표시기 또는 실행취소 메시지)에 상관없이 필요할 때만 보기를 로드하여

developer.android.com

 

댓글