AAC LiveData의 등장으로 데이터바인딩 라이브러리 사용시 MVVM아키텍처와 맞물려 데이터와 UI간의 동기화하는 코드를 많이 사용하고 있습니다.

단수의 Data를 다루는데 있어서 LiveData는 편리했습니다.
기존 BaseObservable을 구현한 클래스에서 notifyChange 또는 notifyPropertyChange를 처리할 필요도없고,
생명주기를 알고있다는 점이 좋았습니다.

하지만,

복수의 Data인 List 또는 ArrayList 타입을 LiveData로 감싸서 사용하는 경우가 왕왕 생기곤 하는데요.
이 경우에 List의 Element를 추가하거나 제거 할 때 매우 귀찮은 일이 발생했습니다.

예를 들면 이런경우 입니다. 기존에 A,B,C 라는 아이템이 이미 있고, 

MutableLiveData<ArrayList<String>> liveItems = new MutableLiveData<>();
ArrayList<String> items = new ArrayList<>();
items.add("A");
items.add("B");
items.add("C");
liveItems.setValue(items);

여기에서 하나의 아이템을 추가하거나 지우고 싶을 때가 있습니다.

ArrayList<String> tempItems = liveItems.getValue();
tempItems.remove("B");
liveItems.setValue(tempItems);

단지 ArrayList였다면 add() 또는 remove() 호출뒤에 별도의 작업을 할 필요는 없지만 DataBinding과 LiveData를 쓰는 경우 UI동기화를 하기 위해 옵저버에게 notify를 하고 싶을 때가 있습니다.

그렇기 때문에 LiveData사용시 다시 setValue 또는 postValue 호출을 통해 옵저버에게 통지를 하게 되는데요. 

이 작업이 매우 귀찮습니다.

그래서 두가지 방법을 생각해 보았습니다.

LiveData와 List 따로 관리하기

add나 remove호출 등은 List에서만 처리하고 처리한 최종결과만을 LiveData에 넣어주는겁니다.

MutableLiveData<ArrayList<String>> liveItems = new MutableLiveData<>();
ArrayList<String> items = new ArrayList<>();

void add(String item){
    items.add(item);
    liveItems.setValue(items);
}

void remove(String item){
    items.remove(item);
    liveItems.setValue(items);
}

이 코드에서 중점적인 사항은 LiveData로부터 getValue()를 호출하지 않는 다는 것입니다. 그냥 새로운 결과를 덮어씌워줄 뿐이죠.

Custom LiveData 만들기

첫번째 방법도 좋지만 어쨌든 setValue를 매번 호출해주어야하는 부담감이 있습니다. 그래서 전 Custom Class를 만들기로 했습니다.

public class ListLiveData<T> extends MutableLiveData<ArrayList<T>> {

    public ListLiveData(){
        setValue(new ArrayList<>());
    }

    public void add(T item){
        ArrayList<T> items = getValue();
        items.add(item);
        setValue(items);
    }

    public void addAll(List<T> list){
        ArrayList<T> items = getValue();
        items.addAll(list);
        setValue(items);
    }

    public void clear(boolean notify) {
        ArrayList<T> items = getValue();
        items.clear();
        if(notify){
            setValue(items);
        }
    }

    public void remove(T item){
        ArrayList<T> items = getValue();
        items.remove(item);
        setValue(items);
    }

    public void notifyChange(){
        ArrayList<T> items = getValue();
        setValue(items);
    }

}

특별한 내용은 없습니다. 단지 add 및 remove 등의 구현을 MutableLiveData를 상속하여 구현한 것입니다. 또한 생성과 동시에 ArrayList를 만드므로 NPE로 부터 안전합니다.

더 좋은 방법이 있거나 다른 대안이 있다면, 댓글에 남겨주시면 감사합니다!

카테고리: Java

5개의 댓글

dhparkz · 2020년 2월 22일 5:36 오후

솬님 안녕하세요.
그림 검색하다 들어왔습니다.
저번에 얘기 같이하면서 좋은그림이라고 생각했는데 출처가 잘 기억이 안나네요.
감사합니다 ^^

아 저는 ArrayList를 Observable형태로 만들때
주로 ObservableArrayList를 사용하곤 하는데
여기에서는 OnListChangedCallback.java 라는 콜백형태로 제공해주는거 같네요.
LiveData + ObservableArrayList 같이 써서 만들어줘도 좋을거 같네용

    Charlezz · 2020년 7월 16일 4:42 오후

    LiveData+ArrayList가 이미 ObservableArrayList와 동등한 역할을 하는 수퍼셋이기 때문에 굳이 ObservableArrayList를 적용하지 않아도 될 것 같아요.

지만 · 2020년 7월 13일 3:38 오후

저도 마땅한 방법을 못 찿았는데 Custom LiveData를 써보겠습니다. 잘읽었어요

    Charlezz · 2020년 7월 16일 4:40 오후

    감사합니다 🙂

코똥잉 · 2020년 10월 13일 5:27 오후

좋은 글 잘 읽었습니다

저도 위와 비슷하게 작업 했었는데
위와 같은 형태로 작업 시에는 데이터가 갱신되었을 때 ListView 에 구체적인 갱신 이벤트를 내려줄 수 없다는 단점이 있어서 찾아 보는데 감이 안잡혀서 livedata소스 참고해서 수정했었네요… ㅠㅠ

답글 남기기

Avatar placeholder

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.