RxJava를 사용하여 라이프 사이클 소유자와 의사 소통

몇 년 전 구글이 내놓은 Jetpack은 안드로이드 개발을 간소화하기 위한 고집스런 라이브러리로 구성된 가족이다.Jetpack의 핵심 클래스 중 하나는 LiveData - 관찰할 수 있는 수명 주기 감지 데이터 소유자입니다.전형적인 용례는 ViewModel을 속성으로 공개하는 LiveData을 가지고 있으며, 당신의 생명주기 소유자인 Fragment 또는 Activity에서 관찰하는 것입니다.
일반적인 사용 방법은 다음과 같습니다.
data class MyState(val value: String)

class MyViewModel : ViewModel {

    private val _state = MutableLiveData<MyState>()
    val state: LiveData<MyState>
    get() = _state
}

class MyFragment : Fragment {

    val viewModel by viewModels<MyViewModel>()

    override fun onViewCreated() {
        viewModel.state.observe(this, Observer(::handleState))
    }

    private fun handleState(state: MySate): Unit = TODO()
}

LiveData을 사용하면 다음과 같은 이점이 있습니다.
  • 데이터가 변경되면 관찰자
  • 에게 통지
  • 옵서버가 활성 상태인 경우에만 변경 통지
  • 관찰자가 다시 활성화되면 안내데스크에 입장하는 등
  • LiveData 문서의 모든 혜택을 보십시오.

    실시간 데이터 및 이벤트Snackbar/대화 상자가 표시되거나 다른 Activity/Fragment으로 이동할 경우 ViewModelLifecycleOwner을 알려야 합니다.일반적인 낡은 LiveData은 마지막 항목을 캐시하기 때문에 여기에 작용하지 않는다.일종의 해결 방법으로 정부의 안드로이드 구조 예시에서 SingleLiveEventLiveData이 실현되었다.

    데이터 계층
    그런데 응용 프로그램의 다른 부분은요?데이터 계층에서 LiveData을 사용할 수 있으며 실제로는 Jetpack의 지속성 라이브러리이며 로컬에서는 LiveData을 반환 유형으로 지원합니다.그러나 응용 프로그램의 모든 층에서 LiveData을 사용할 수 있지만 이것은 이상적이지 않다.이러한 조작은 항상 주 라인에서 실행되며, RxJava 또는 Flow에 비해 변환 함수 수량이 제한되어 있다.
    이 문제를 해결하기 위해 KotlinX Coroutines는 LiveDataRxJava에 어댑터를 제공했다.이는 개발자가 데이터 층에서 Flow 또는 RxJava을 사용하고 Flow에서 LiveData으로 전환하여 생명주기 의식에 이익을 얻을 수 있음을 의미한다.

    State 및 RxJava
    지난주에 Marvel API를 사용하여 예시 프로그램을 개발하고 있습니다. 당신은 Github에서 전체 코드를 볼 수 있습니다.RxJava가 지원하는 전체 반응 아키텍처를 사용합니다.나의 최초의 방법은 ViewModel을 이용하여 LiveData->ViewModel통신을 하는 것이다.그러나 저도 Fragment의 우수한 테스트 지원에서 이익을 얻고 싶어서 RxJava을 사용하여 LiveData이 한 일을 해보기로 했습니다.
    상태를 관찰하기 위해 Rxjava는 RxJava을 제공했다. 이것은 BehaviorSubject으로 관찰한 마지막 값을 캐시하고 구독자마다 Subject에 보낸다.그것은 마지막 값을 캐시하고 변경 사항을 관찰합니다.메인 나사에서 관찰하면 Observer이 있다.라이프 사이클 부분은요?이 문제를 해결하기 위해 저는 utility class을 창설하여 RxAndroid에 구축하여 정확한 생명주기 리셋에서 구독을 처리할 수 있도록 했습니다.
    class LifecycleDisposable(
        private val disposable: Disposable
    ) : DefaultLifecycleObserver {
    
        override fun onDestroy(owner: LifecycleOwner) {
            disposable.dispose()
            super.onDestroy(owner)
        }
    }
    
    
    다음 명령의 코드를 사용합니다.
    class RxViewModel : ViewModel() {
    
        private val _state = BehaviorSubject.create<MyState>()
        val state: Observable<MyState>
        get() = _state
    }
    
    class RxFragment : Fragment() {
    
        val viewModel by viewModels<MyViewModel>()
    
        fun onViewCreated() {
            viewModel.state
                .subscribe(::handleState)
                .autoDispose() // extension function, check the Github link
        }
    
        private fun handleState(state: MySate) = TODO()
    }
    
    
    LifecycleOwner과 달리 LiveData부터 관찰하고 onViewCreated에서 구독을 취소한다.코드는 onDestroyView에서 구독하고 onStart에서 관찰을 멈추는 것과 유사하지만 제 경험에 의하면 보기가 활성화되지 않았을 때 보기 상태를 업데이트하는 것은 저에게 문제가 되지 않았습니다.

    이벤트 및 RxJava
    사건과 상태가 좀 다르다.주요 요구는 한 번만 교부해야 한다(소모 가능).또 다른 중요한 요구는 보기가 활동 상태(onStoponStart 사이)에 있을 때만 교부하는 것이다.나의 첫 번째 시도는 onStop을 사용하는 것이다.

    A Subject that queues up events until a single Observer subscribes to it, replays those events to it until the Observer catches up and then switches to relaying events live to this single Observer until this UnicastSubject terminates or the Observer unsubscribes.


    그러나 결과는 이상적이지 않다.관찰자가 없는 상황에서 사건의 줄을 서는 것은 매우 효과적이다.가입 후 모든 활동이 제공됩니다.구독 서버가 있을 때 이벤트가 전달되고 있습니다.문제는 구독자가 구독을 취소하고 신규 구독자가 구독을 시도할 때(UnicastSubjectonStart은 여러 번 터치할 수 있다)다.onStop에서 UnicastWorkSubject으로 업그레이드했습니다.

    A Subject variant that buffers items and allows one Observer to consume it at a time, but unlike UnicastSubject, once the previous Observer disposes, a new Observer can subscribe and resume consuming the items.


    이것이 바로 내가 필요로 하는 것이다.라이프 사이클 섹션의 경우 다시 RxJavaExtensions으로 이동하여 다음을 만듭니다.
    class EffectsObserver<E>(
        private val effects: Observable<E>,
        private val executeEffect: (E) -> Unit
    ) : DefaultLifecycleObserver {
    
        private var disposable: Disposable? = null
    
        override fun onStart(owner: LifecycleOwner) {
            super.onStart(owner)
            disposable = effects.flatMap {
                Observable.fromCallable { executeEffect(it) }
            }.subscribe()
        }
    
        override fun onStop(owner: LifecycleOwner) {
            disposable!!.dispose()
            super.onStop(owner)
        }
    }
    
    
    사용법은 다음과 같습니다.
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        lifecycle.addObserver(EffectsObserver(viewModel.effects) { effect ->
            when (effect) {
                is NavigateToDetails -> TODO("Navigate")
            }
        })
    }
    
    
    이것은 내비게이션과 표시 LifecycleObserver 등 이벤트가 프로그램이 백엔드에 있을 때 줄을 서고 프로그램이 백엔드에 있을 때만 발생하도록 확보할 것이다.그것은 무서운 java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState을 피하는 데 도움이 된다.
    주의: Snackbar을 사용할 때, 중요한 것은 Fragment에 그것을 등록하는 것이지, onCreate에 등록하는 것이 아니다. (백엔드에서 세션을 여러 번 호출할 수 있다.)

    결론onViewCreatedLiveData->ViewModelLifecycleOwner의 통신 방식을 시뮬레이션할 수 있습니다.그러나, RxJava이 활성 상태일 때만 사건을 교부하는 등 정확한 조작을 위해 가장자리 상황을 고려해야 합니다.
    만약 다른 생각이 있다면 아래에 메시지를 남겨 주세요.즐거운 코딩!

    좋은 웹페이지 즐겨찾기