티스토리 뷰

android

[android] SingleLiveEvent

tbMaster 2020. 7. 27. 15:52
반응형

참조

https://medium.com/androiddevelopers/livedata-with-snackbar-navigation-and-other-events-the-singleliveevent-case-ac2622673150

 

LiveData with SnackBar, Navigation and other events (the SingleLiveEvent case)

A convenient way for a view (activity or fragment) to communicate with a ViewModel is to use LiveData observables. The view subscribes to…

medium.com

https://proandroiddev.com/singleliveevent-to-help-you-work-with-livedata-and-events-5ac519989c70

 

SingleLiveEvent to help you work with LiveData and events

Have you had to deal with a Dialog or a SnackBar that after been triggered/shown or dismissed and followed by a device rotation is…

proandroiddev.com


SingleLiveEvent를 사용하게 된 이유 : LiveData를 적용하는데 있어서 Trigger용... 그러니깐... 한번 상태가 변경된 후에 다시 이전 상태로 돌아와야 하는 경우가 생겼다. 그런데 이러한 Trigger용을 화면에 계속적으로 노출시키는 LiveData로 표현하려니 불편했달까...?? 마침 MutableLiveData와 MediatorLiveData 사용 방법 등을 찾던 와중에 SingleLiveEvent라는 것이 있다는 것을 얼핏 알고 있었는데, SingleLiveEvent를 이럴 때 사용한다는 것을 깨달았다. 

그래서 SingleLiveEvent 사용 방법을 알아보고 적용하기로 하였다. 

 


SingleLiveEvent : MutableLiveData의 확장버전으로 한번 변경이 일어난 후 다시 원래 상태로 변경되도록 한다. 

 

사용 이유

예를 들어, 전체화면과 상세화면이 있다고 가정하자. (참조 블로그의 내용이자 내가 지금 개발하는 부분...)

 

[ 참조 블로그(livedata with snackbar navigation and other events the singleliveevent)의 잘못된 livedata 사용 예시 코드를 그림으로 표현함 ]

위의 그림은 한 번만 이용.. 즉, Trigger로 LiveData를 이용했을 경우에 발생하는 문제점 중 하나이다. 

이와 같은 문제점을 해결하기 위해서 Trigger(상태변경 감지 후, 상세화면으로 넘기는 형태) 직전에 LiveData의 값을 다시 초기화 시켜줘서 해결할 수 있다. 

그러나 이러한 처리 방법은 bolierplate code를 발생시키며, 적용하는 것을 잊어버릴 수도 있다. 

 

그렇기 때문에 SingleLiveEvent 사용을 권고한다.

 

※ SingleLiveEvent는 단 하나의 observer만 관찰할 수 있도록 한다. 만약 여러 observer가 관찰하도록 한다면, wrapper를 사용하라고 한다. 그 이유는 여러 observer가 변경사항을 관찰했을 때, 단 한번만 실행된다는 보장이 없기 때문이라는데... 이 부분은 잘 이해가 안된다... 

https://gist.github.com/JoseAlcerreca/5b661f1800e1e654f07cc54fe87441af#file-event-kt


 

SingleLiveEvent 코드

SingleLiveEvent 코드는 android architecture-sample에서 발췌한것이다.

https://github.com/android/architecture-samples/blob/dev-todo-mvvm-live/todoapp/app/src/main/java/com/example/android/architecture/blueprints/todoapp/SingleLiveEvent.java

 

android/architecture-samples

A collection of samples to discuss and showcase different architectural tools and patterns for Android apps. - android/architecture-samples

github.com



/*
 *  Copyright 2017 Google Inc.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

import android.util.Log;

import androidx.annotation.MainThread;
import androidx.annotation.Nullable;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer;

import java.util.concurrent.atomic.AtomicBoolean;

/**
 * A lifecycle-aware observable that sends only new updates after subscription, used for events like
 * navigation and Snackbar messages.
 * <p>
 * This avoids a common problem with events: on configuration change (like rotation) an update
 * can be emitted if the observer is active. This LiveData only calls the observable if there's an
 * explicit call to setValue() or call().
 * <p>
 * Note that only one observer is going to be notified of changes.
 */
public class SingleLiveEvent<T> extends MutableLiveData<T> {

    private static final String TAG = "SingleLiveEvent";

    private final AtomicBoolean mPending = new AtomicBoolean(false);

    @MainThread
    public void observe(LifecycleOwner owner, final Observer<? super T> observer) {

        if (hasActiveObservers()) {
            Log.w(TAG, "Multiple observers registered but only one will be notified of changes.");
        }

        // Observe the internal MutableLiveData
        super.observe(owner, new Observer<T>() {
            @Override
            public void onChanged(@Nullable T t) {
                if (mPending.compareAndSet(true, false)) {
                    observer.onChanged(t);
                }
            }
        });
    }

    @MainThread
    public void setValue(@Nullable T t) {
        mPending.set(true);
        super.setValue(t);
    }

    /**
     * Used for cases where T is Void, to make calls cleaner.
     */
    @MainThread
    public void call() {
        setValue(null);
    }
}
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
글 보관함