오늘도 더 나은 코드를 작성하였습니까?

Observable 데이터 객체로 작업하기 본문

Android Jetpack Architecture/DataBinding

Observable 데이터 객체로 작업하기

hik14 2020. 8. 10. 14:42

Observable은 객체가 데이터 변경에 관해 다른 객체에 알릴 수 있는 기능을 의미합니다.

데이터 결합 라이브러리를 통해 객체, 필드 또는 컬렉션을 식별 가능하게 만들 수 있습니다.

 

간단한 기존 객체를 데이터 결합에 사용할 수는 있지만 객체를 수정해도 UI가 자동으로 업데이트되지는 않습니다.

 

데이터 결합을 사용하면 데이터 변경 시 리스너라는 다른 객체에 알리는 기능을 데이터 객체에 제공할 수 있습니다.

식별 가능한 클래스에는 세 가지 유형, 즉 객체, 필드 및 컬렉션이 있습니다.

 

식별 가능한 데이터 객체 중 하나가 UI에 결합되고 데이터 객체의 속성이 변경되면 UI가 자동으로 업데이트됩니다.

 

Observable 필드 사용

데이터 바인딩 라이브러리에서는 이미 Observable인터페이스를 구현한 몇몇 클래스를 제공하기 때문에 적합한 클래스를 찾을 수 있다면 직접 구현할 필요는 없다. 제공되는 클래스는 아래와 같다.

 

observable 필드는 하나의 필드를 가진 Observable 객체이다. 필드접근시 Boxing UnBoxing 과정을 방지하려고 원시 타입만을 사용한다. 

 

바인딩된 Observable 객체의 변경을 막고자 변수 선언시 자바는 public final 코틀린은 read-only(val) 프로퍼티만 사용할 것을 권장한다.

    private static class User {
        public final ObservableField<String> firstName = new ObservableField<>();
        public final ObservableField<String> lastName = new ObservableField<>();
        public final ObservableInt age = new ObservableInt();
    }

필드 값에 대한 접근은 set(), get()으로 한다. 

  user.firstName.set("Google");
    int age = user.age.get();

 

Observable Collection 사용

 

몇몇 앱은 동적인 구조를 사용하여 데이터를 관리한다. Observable 컬렉션은 이러한 구조에 접근하도록  key를 사용합니다. ObservableArrayMap 클래스는 키가 String  참조 타입일 때 유용하다.

 

class MainActivity : AppCompatActivity() {



    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val mbinding: ActivityMainBinding =
                DataBindingUtil.setContentView(this, R.layout.activity_main)

        val userMap = ObservableArrayMap<String, Any>()

        userMap["firstName"] = "Google"
        userMap["lastName"] = "Inc."
        userMap["age"] = 17

        mbinding.userMap = userMap

    }
<?xml version="1.0" encoding="utf-8"?>
<layout>
    <data>
        <variable
            name="userMap"
            type="androidx.databinding.ObservableArrayMap&lt;String, Object>"/>

    </data>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{userMap.firstName.toString()}"/>



        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{userMap.lastName.toString()}"/>


        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(userMap.age)}"/>

    </LinearLayout>
</layout>

Observable 객체 사용하기

 

Observable 인터페이스를 구현한 클래스는 데이터의 변경에 대한 알림을 받는 리스너를 등록 가능하다.

Observable 인터페이스는 추가와 제거 리스너를 위한 방법을 가지지만 반드시 데이터의 변경 알림 시기를 직접 정의해야 된다. 하지만 개발의 편의성을 위해 데이터 바인딩 라이브러리는 BaseObservable클래스를 제공한다.

 

BaseObservable을 구현한  데이터 클래스는 프로퍼티 변경 시 알림을 책임진다.

이는 @Bindable 에노테이션을 getter 메서드에 적용하고 notifyPropertyChange() 메서드를 setter메서드 내에서 호출하는 것으로 적용된다.

public class User extends BaseObservable {
    private String firstName = "없음";
    private String lastName ="없음";

    @Bindable
    public String getFirstName() {
        return this.firstName;
    }

    @Bindable
    public String getLastName() {
        return this.lastName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
        notifyPropertyChanged(BR.firstName);
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
        notifyPropertyChanged(BR.lastName);
    }

    public void changeName(View view){
        setFirstName("il Kwon");
        setLastName("hong");
    }
}