LiveData의 별도 MutableLiveData 하위 클래스가있는 이유는 무엇입니까?


96

및 메서드를 공개 하는 것만 과 MutableLiveData는 다른 것처럼 보이지만 보호됩니다.LiveDatasetValue()postValue()LiveData

이러한 변경을 위해 별도의 클래스를 만들고 해당 메서드를 LiveData자체적 으로 공용으로 정의하는 것이 아닌 몇 가지 이유는 무엇입니까 ?

일반적으로 말하자면, 그러한 상속 형태 (특정 메서드의 가시성을 높이는 것이 유일한 변경 사항 임)는 잘 알려진 관행이며 유용 할 수있는 몇 가지 시나리오는 무엇입니까 (모든 코드에 액세스 할 수 있다고 가정)?


10
디자인 결정입니다. LiveData클라이언트가 내부 상태를 변경할 수 있기 때문에 스레드 안전 불변
Blackbelt

답변:


139

에서 LiveData - 안드로이드 개발자 용 문서 , 당신을 위해 그것을 볼 수 있습니다 LiveData, setValue()postValue()방법은 공개되지 않습니다.

반면 MutableLiveData-Android Developer Documentation 에서 내부적으로 MutableLiveData확장 LiveData되고의 두 가지 매직 메서드 LiveData공개적으로 사용 가능하며 setValue()& postValue()입니다.

setValue(): 값을 설정하고 모든 활성 관찰자에게 값을 전달하며 주 스레드 에서 호출해야합니다 .

postValue(): 작업을 메인 스레드에 게시하여에서 설정 한 값을 무시 setValue()하고 백그라운드 스레드 에서 호출해야합니다 .

따라서, LiveData이다 불변 . MutableLiveData이다 LiveData가변스레드 안전 .


38
LiveData가 변경 불가능한 것이 아니라 ViewModel 클래스 외부 에서 수정할 수 없다는 것 입니다. ViewModel 클래스는 원하는대로 수정할 수 있습니다 (예 : 타이머 ViewModel). ViewModel 클래스 외부에서 수정하려는 경우 MutableLiveData를 사용합니다.
Elliptica

2
Room이 단일 진실 소스 인 저장소 패턴 (Server + Room)을 사용하는 앱인이 시나리오를 살펴 보겠습니다. 앱은 Room에서만 데이터를 가져오고 Room은 서버에서 업데이트를 가져옵니다. 서버 업데이트 Room 또는 LiveData의 데이터를 사용할 수 있으므로 mutableLiveData를 반드시 사용해야합니까?
Dr4ke the b4dass

5
LiveData는 추상적이므로 확장하지 않고 LiveData 개체를 직접 만들 수 없습니다. MutableLiveData는 LiveData를 확장합니다.
Serdar Samancıoğlu dec.

1
LiveData 및 MutableLiveData에 대한 링크는 더 이상 사용되지 않는 문서로 직접 연결됩니다. 실제 링크가있는 편집을 제안했을 때 거부 된 이유는 무엇입니까?
Daniel

1
@Daniel은 검토 대기열의 다른 검토자가 거부 한 이유를 잘 모릅니다. 변경을 승인했습니다. 감사합니다! :)
스네 디야

10

다음은 전체 MutableLiveData.java파일입니다.

package androidx.lifecycle;
/**
 * {@link LiveData} which publicly exposes {@link #setValue(T)} and {@link #postValue(T)} method.
 *
 * @param <T> The type of data hold by this instance
*/
@SuppressWarnings("WeakerAccess")
public class MutableLiveData<T> extends LiveData<T> {
    @Override
    public void postValue(T value) {
        super.postValue(value);
    }
    @Override
    public void setValue(T value) {
        super.setValue(value);
    }
}

그래서 그래, 그 차이는 만들어 제공 postValuesetValue공개.

머리에서 떠 올릴 수있는 한 가지 사용 사례 는 Kotlin의 Backing Property 를 사용하여 캡슐화하는 것 입니다. 클래스 에서 조작 LiveData할 수 있더라도 Fragment / Activity (UI 컨트롤러)에 노출 할 수 있습니다 .MutableLiveDataViewModel

    class TempViewModel : ViewModel() {
        ...
        private val _count = MutableLiveData<Int>()
        val count: LiveData<Int>
            get() = _count
        public fun incrementCount() = _count.value?.plus(1)
        ...
    }

이렇게하면 UI 컨트롤러가 값을 편집 할 수없는 상태에서만 관찰 할 수 있습니다. 분명히 UI 컨트롤러는 TempViewModel같은 공용 메서드를 사용하여 값을 편집 할 수 있습니다 incrementCount().

참고 : 변경 가능 / 불변 혼란을 명확히하기 위해-

data class User(var name: String, var age: Int)

class DemoLiveData: LiveData<User>()

var demoLiveData: LiveData<User>? = DemoLiveData()

fun main() {
    demoLiveData?.value = User("Name", 23) // ERROR
    demoLiveData?.value?.name = "Name" // NO ERROR
    demoLiveData?.value?.age = 23  // NO ERROR
}

무엇입니까 _score?
IgorGanapolsky

0

MutableLiveData는 LiveData에서 확장됩니다. LiveData의 보호 된 메서드는 자체 또는 하위 클래스에 의해서만 처리 될 수 있습니다. 따라서이 경우 LiveData의 하위 클래스 인 MutableLiveData는 이러한 보호 된 메서드에 액세스 할 수 있습니다.

여러분이하고 싶은 것은 인스턴스를 관찰하고 변경 사항이 있는지 확인하는 것입니다. 그러나 동시에 "외부인"이 관찰중인 인스턴스를 변경하는 것을 원하지 않습니다. 어떤 의미에서 이것은 변경 가능하고 새로운 상태를 업데이트하기 위해 변경 가능한 객체를 갖기를 원하므로 문제가 발생하여이 인스턴스를 업데이트해서는 안되는 사람이 없도록합니다. 이 두 기능은 서로 충돌하지만 추가 레이어를 생성하여 해결할 수 있습니다.

따라서 메서드에 액세스 할 수있는 클래스를 사용하여 클래스 LiveData를 확장합니다. 하위 계층 (이 경우 MutableLiveData)은 부모 (/ super)의 보호 된 메서드에 액세스 할 수 있습니다.

이제 인스턴스 생성을 시작하고 MutableLiveData의 관찰자 인스턴스를 생성합니다. 동시에이 동일한 인스턴스를 참조하는 LiveData 인스턴스를 만듭니다. MutableLiveData는 LiveData를 확장하기 때문에 모든 MutableLiveData 인스턴스는 LiveData 개체이므로 LiveData 변수에서 참조 할 수 있습니다.

이제 트릭이 거의 완료되었습니다. LiveData 인스턴스 만 노출하고 아무도 보호 된 메서드를 사용할 수 없으며 수퍼로 캐스팅 할 수도 없습니다. 그리고 실제 하위 클래스 인스턴스를 비공개로 유지하므로 인스턴스의 메서드를 사용하여 인스턴스를 소유 한 사람 만 변경할 수 있습니다.

//create instance of the sub class and keep this private
private val _name: MutableLiveData<String> = MutableLiveData<String>()
//create an instance of the super class referring to the same instance
val name: LiveData<String> = _name
//assign observer to the super class, being unable to change it
name.value.observe(.....)

이제 수퍼 클래스는 변경 사항이 적용될 때 알림을 보냅니다.

//change the instance by using the sub class
_name.postValue(...)
//or _name.setValue(...)

인용구 일반적으로 말해서, 그러한 상속 형태 (특정 메서드의 가시성을 높이는 것이 유일한 변경 사항 임)는 잘 알려진 관행이며 유용 할 수있는 몇 가지 시나리오는 무엇입니까 (모든 코드에 액세스 할 수 있다고 가정)?

예, 꽤 잘 알려져 있으며 위에서 설명한 것은 일반적인 시나리오입니다. 관찰자 패턴을 제거하고 설정 / 가져 오기 형식으로 만드는 것만으로도 많은 이점이 있습니다. 구현 위치에 따라 결국 황금률이 ​​없습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.