ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • AAC - Databinding
    안드로이드 학습/Android 기술면접 대비 2023. 6. 21. 11:03

    기존에 DataBinding을 사용하면서 별 사용법이 특별할게 없다고 생각해서 따로 공부할 필요성을 느끼고 있지는 못했다.

    하지만 앱 아키텍처를 학습하면서 여러 예제를 봤을때 단순하게 데이터를 xml에서 처리해주는 것 말고도 여러가지 방식으로 많이 사용하는 것을 보았다.

     

    예를 들어 RecyclerView에 list를 넣어주는 부분도 있었고, Toast Message도 BindingAdapter을 활용해서 넣어주는 것을 보았다. DataBinding 활용법을 좀더 깊이 학습한다면 내가 지금 학습하는 앱아키텍처에 적용해볼 수 있고 여러가지 활용도 면에서 좋을 것 같아서 제대로 학습해보리고 했다. 

     

    1. DataBinding이란?

    DataBinding은 JetPack - AAC(Android Archictecture Components) 의 한 부분으로서 UI 요소와 데이터를 프로그램적 방식으로 연결하지 않고, 선언적 형식으로 결합할 수 있게 도와주는 라이브러리를 말한다. 

     

    DataBinding은 Data와 View를 연결하는 작업을 Activity나 Fragment에서 하는 것이 아닌 Layout(xml)에서 처리하는 기술을 DataBinding이라고 하는 것이다. 

     

    프로그램적 방식

    TextView textView = findViewById(R.id.name);
    textView.setText("user_name");

     

    선언적 방식

    <TextView
    	android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@{viewmodel.userName}" />

     

    2. Data binding 장단점

    2-1 장점 : 

    데이터 바인딩을 사용하면, 데이터를 UI 요소에 연결하기 위해 필요한 코드를 최소화할 수 있다. 

    Activity나 Fragment에서 따로 View를 정의하지 않아도 되고, 

    data가 변경될 때마다 자동으로 데이터 변경을 반영해준다. 

     

    1. 코드 감소

    • findViewById() 호출이 필요 없어 코드가 간결해진다.
    • XML에서 데이터를 넣기 때문에 UI 업데이트 코드를 줄일 수 있다. 

    2. 양방향 데이터 바인딩

    • 데이터 변경 시 UI가 자동 업데이트 되고, UI 변경 시 데이터도 자동으로 반영시킬 수 있다. 

    3. 유지보수성 향상

    • UI 로직이 XML에 선언적으로 정의되어 코드의 가독성이 향상된다. 
    • XML만 봐도 어떤 데이터가 있는지 파악이 가능하다. 

    4. Null Safety

    • View를 직접 참조하기 때문에 없는 아이디로 NullPointException 발생 안한다
    • View type이 일치함으로 Class Cast Exception 발생 안한다

    양방향 데이터 바인딩 :

    • (단방향 바인딩) 일반적으로는 ViewModel의 데이터가 변경되면 View가 업데이트 되는 흐름
    • (양방향 바인딩) View의 데이터가 변경해서 ViewModel의 데이터를 변경시켜준다면 이것을 양방향 데이터 바인딩이라고 한다. 예를 들면 EditText의 변경으로 LiveData가 변경하고 변경된 LiveData의 데이터가 같은 EditText를 변경하는 것도 양방향 바인딩이라고 할 수 있다. 

    2-2 단점

    1. 빌드 속도 저하

    • 컴파일 시 바인딩 클래스를 생성하므로 대규모 프로젝트에서는 빌드 시간이 증가할 수 있습니다.

    2. 디버깅 어려움 (Debugging Difficulty)

    • XML 파일 내의 바인딩 오류가 명확하지 않아 문제 해결이 어려울 수 있습니다.
    • 런타임 오류는 컴파일 시 잡히지 않고 앱 실행 시 발생할 수 있습니다.

    3.기술 복잡성 (Learning Curve)

    • DataBinding은 배우기 쉽지만 고급 기능(예: Observable, @BindingAdapter)은 학습 비용이 큽니다.

     

    https://developer.android.com/topic/libraries/data-binding/expressions?hl=ko

     

    레이아웃 및 바인딩 수식  |  Android Developers

    이 페이지는 Cloud Translation API를 통해 번역되었습니다. 레이아웃 및 바인딩 수식 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 표현식 언어를 사용하면 전

    developer.android.com

     

     

    DataBinding 활용법 :

     

    1) 먼저 build.gradle 에 추가 해야한다. 

    android {
        ...
        buildFeatures {
            dataBinding true
        }
    }

     

    2) Layout 및 바인딩 수식

    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android">
       <data>
           <variable name="user" type="com.example.User"/>
       </data>
       <LinearLayout
           android:orientation="vertical"
           android:layout_width="match_parent"
           android:layout_height="match_parent">
           <TextView android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="@{user.firstName}"/>
           <TextView android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="@{user.lastName}"/>
       </LinearLayout>
    </layout>

     

    DataBinding 레이아숫 파일은 기본적으로 layout 태그로 시작하는 루트 태그를 사용한다. 

     

     

    2-1) 변수 지정

    <variable name="user" type="com.example.User" />

     

     

    2-2) viewmodel에 있는 데이터를 @{} 문법을 사용해서 연결할 수 있다. 

    <TextView android:text="@{user.firstName, default=my_default}"/>

     

    Text에 default 값 지정해도 되고 안해도 된다.

     

    2-3) 지정된 변수 연결

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        val binding: ActivityMainBinding = DataBindingUtil.setContentView(
                this, R.layout.activity_main)
    
        binding.user = User("Test", "User")
    }

     

    binding 클래스는 각 layout 파일별로 생성된다. activity_main.xml이라면 ActivityMainBinding으로 생성된다. 

    레이아웃이 inflate 되는 동안 바인딩이 만들어지는 것을 추천한다. - onCreate 같은 곳에서 초기 databing 값을 할당하라는 것 같음

     

    2-4) 표현식

    android:text="@{String.valueOf(index + 1)}"
    android:visibility="@{age > 13 ? View.GONE : View.VISIBLE}"
    android:transitionName='@{"image_" + id}'

     

    표현식 리스트

    더보기
    • Mathematical: + - / * %
    • String concatenation: +
    • Logical: && ||
    • Binary: & | ^
    • Unary: + - ! ~
    • Shift: >> >>> <<
    • Comparison: == > < >= <= (the < needs to be escaped as &lt;)
    • instanceof
    • Grouping: ()
    • Literals, such as character, String, numeric, null
    • Cast
    • Method calls
    • Field access
    • Array access: []
    • Ternary operator: ?:

     

    2-5) Null 병합 연산자 

    android:text="@{user.displayName ?? user.lastName}"
    

     

    아래와 같은 표현식이다. 

    android:text="@{user.displayName != null ? user.displayName : user.lastName}"
    

     

    만들어진 data binding 코드는 자동적으로 null 값을 체크하고, null pointer exception을 피한다. 예를 들어, @{user.name} 표현식 에서 user가 null 이라면 default 값 null이 배정되고, int value 라면 0이 default 값으로 배정된다. 

     

    2-6) 이벤트 처리 

    class MyHandlers {
        fun onClickFriend(view: View) { ... }
    }
    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android">
       <data>
           <variable name="handlers" type="com.example.MyHandlers"/>
           <variable name="user" type="com.example.User"/>
       </data>
       <LinearLayout
           android:orientation="vertical"
           android:layout_width="match_parent"
           android:layout_height="match_parent">
           <TextView android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="@{user.firstName}"
               android:onClick="@{handlers::onClickFriend}"/>
       </LinearLayout>
    </layout>

     

    아래와 같은 방식으로 이벤트를 처리 할 수 있다. 

    android:onClick="@{handlers::onClickFriend}

     

    onClick 같은 경우 이미 만들어져 있는 메소드고 유저가 따로 @BindingAdapter를 사용해서 만들 수 있다. 

     

    그리고 두 개 이상의 매개변수와 함께 람다 표현식을 사용할 수 있습니다.

    class Presenter {
        fun onCompletedChanged(task: Task, completed: Boolean){}
    }
    
    <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content"
          android:onCheckedChanged="@{(cb, isChecked) -> presenter.completeChanged(task, isChecked)}" />

     

    2-7) StateFlow 사용

     

    DataBinding과 StateFlow나 LiveData를 같이 사용하려고 한다면 lifecyclerowner를 정의해줘야 한다. 

    class ViewModelActivity : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            // Inflate view and obtain an instance of the binding class.
            val binding: UserBinding = DataBindingUtil.setContentView(this, R.layout.user)
    
            // Specify the current activity as the lifecycle owner.
            binding.lifecycleOwner = this
        }
    }
    class ScheduleViewModel : ViewModel() {
    
        private val _username = MutableStateFlow<String>("")
        val username: StateFlow<String> = _username
    
        init {
            viewModelScope.launch {
                _username.value = Repository.loadUserName()
            }
        }
    }
    <TextView
        android:id="@+id/name"
        android:text="@{viewmodel.username}" />

     

    2-8) Binding Adapters

    @BindingAdapter("android:paddingLeft")
    fun setPaddingLeft(view: View, padding: Int) {
        view.setPadding(padding,
                    view.getPaddingTop(),
                    view.getPaddingRight(),
                    view.getPaddingBottom())
    }
    @BindingAdapter("imageUrl", "error")
    fun loadImage(view: ImageView, url: String, error: Drawable) {
        Picasso.get().load(url).error(error).into(view)
    }
    <ImageView app:imageUrl="@{venue.imageUrl}" app:error="@{@drawable/venueError}" />
    

     

     

    2-9) Two-way databinding

    <CheckBox
        android:id="@+id/rememberMeCheckBox"
        android:checked="@={viewmodel.rememberMe}"
    />

     

    @={} 를 사용해서 뷰에서의 변경을 데이터에 반영하고 데이터의 변경을 다시 뷰에 반영하는 역할을 수행할 수 있다. 

    '안드로이드 학습 > Android 기술면접 대비' 카테고리의 다른 글

    안드로이드 4대 컴포넌트  (0) 2023.08.13
    Intent (인텐트) 와 Bundle  (0) 2023.07.11
    안드로이드 Context  (0) 2023.06.16
    Jetpack - AAC  (0) 2023.06.13
    Activity와 Fragment 그리고 생명주기  (0) 2023.06.12
Designed by Tistory.