SingleLiveEvent 개선하기

개요

SingleLiveEvent에 대한 설명은 이전 포스팅을 참조하자.

Jetpack 라이브러리의 Android Arhitecture Component의 등장이후로 ViewModel과 LiveData를 열심히 사용중이다. View에 대한 ViewModel의 의존관계를 완벽하게 끊어냄으로써 기존에 사용하던 이벤트 처리 방식을 변경 해야 했다.

이벤트 리스너를 뷰컨트롤러(Activity/Fragment)에 구현하는 방식을 많이 사용했는데, ViewModel은 메모리 누수등의 이유로 Context의 참조를 엄격하게 금지하고 있다. 그러므로 뷰컨트롤러에서 ViewModel이 가지고 있는 LiveData를 옵저빙 하는 방식을 사용하게 되고, 단일 이벤트를 보장하기 위해 LiveData를 확장한 SingleLiveEvent를 사용하게 된다. 

이벤트 처리에 대한 내용을 다이어그램으로 표현하면 다음과 같다.

 

개선 동기

사용자의 빠른 더블클릭으로 인해 발생할 수 있는 문제들을 방지하기 위해 기존에는 DataBindingComponent과 RxJava#throttleFirst() 연산자를 활용했었다. RxJava를 사용하면 뷰컨트롤러 생명주기에 따라 Disposable객체를 통해 메모리 상에서 RxJava와 관련된 내용들을 해제 해줘야하는게 항상 허들이였다. 

SingleLiveEvent를 메인으로 이벤트처리의 주된 수단으로 사용하는 지금은 RxJava와 DataBindingComponent를 사용하지 않고, SingleLiveEvent에서 간단하게 처리하면 좋겠다는 생각이 들었다.

개선 코드

public class SingleLiveEvent<T> extends MutableLiveData<T> {

    private static final String TAG = "SingleLiveEvent";

    private static final long MIN_CLICK_INTERVAL = 200;
    private long lastClickTime;

    private final AtomicBoolean mPending = new AtomicBoolean(false);

    ...
    @MainThread
    public void setValue(@Nullable T t) {
        long currentClickTime = SystemClock.uptimeMillis();
        long elapsedTime = currentClickTime - lastClickTime;
        lastClickTime = currentClickTime;

        if(elapsedTime <=MIN_CLICK_INTERVAL){
            return;
        }
        mPending.set(true);
        super.setValue(t);
    }

    ...
}

기존 SingleLiveEvent코드와 거의 동일하며, 마지막 이벤트 처리 시각을 기록하여 현재시간과 비교했을 때 Threshold(임계값)을 초과 하는지 확인한 후 invoke 하는 내용이다.

특별한 것은 없지만, Databinding과 RxJava에 대한 의존성을 제거 할 수 있어 매우 쾌적해졌다.

postValue(T)를 사용할 수도 있지만, 임계값이 보장이 되지 않기 때문에 이러한 방법을 사용하는 것이 가장 확실한 방법이라고 생각한다.

카테고리: 미분류

0개의 댓글

답글 남기기

Avatar placeholder

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