RxJava의 Observable과 LiveData와 ObservableField를 좋은 느낌으로 사용합시다.

LiveData에 대해 착각했던 몇 가지 부터 계속됩니다.

위에서 LiveData는
  • 구독 해제를 자동으로 해주기 때문에 편리
  • DataBinding (= ObservableField)로 사용할 수 없습니다
  • 최소한의 합성 만 가능하기 때문에 부족합니다

  • 라는 것을 썼습니다.

    이번 기사에서는, 위에서 든 미묘한 3가지 점을 해소하기 위해서, RxJava와 LiveData와 DataBinding을 좋은 느낌으로 병용해 보고 싶습니다. 이번에도 코드는 Kotlin입니다.

    RxJava with Android DataBinding



    RxProperty를 사용합시다!
  • RxProperty로 RxJava와 안드로이드 데이터 바인딩 연동 - Qiita

  • 예 종료.

    RxProperty에 대해 쓰는 몇번째, 자신.
    저자 @k-kagurazaka @github 씨도 빚을지고, 사이코입니다, 사랑 해요 RxProperty , 더 를! !
    RxProperty<T> 는 기본적으로는 Observable<T> (라고 하는지 Subject<T> )입니다만, .value 프로퍼티로 ObservableField<T> 로 변환할 수 있습니다.
    // MainViewModel.kt
    class MainViewModel : ViewModel() {
    
        // GitHub ユーザー名。EditText.text から双方向(TwoWay)バインドされる。
        val user = RxProperty<String>()
    
        init {
            user.set("hogehoge")
        }
    }
    

    activity_main.xml
    <?xml version="1.0" encoding="utf-8"?>
    <layout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
    
        <LinearLayout
            xmlns:tools="http://schemas.android.com/tools"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context="net.amay077.livedatasample.view.MainActivity"
            android:orientation="vertical">
    
            <EditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="GitHub user name"
                android:text="@={viewModel.user.value}"/>  ←-- user.value とすることで ObservableField に!
        </LinearLayout>
    </layout>
    

    이와 같이 레이아웃 XML에, viewModel.user.value 라고 기술하면 데이터 바인딩 할 수 버립니다. 위의 예에서는 제대로 양방향 바인딩도 효과가 있습니다.

    RxJava with LiveData



    이것은 「RxJava 의 Observable<T> 로부터 LiveData<T> 로 변환하는 확장 메소드」를 만들어 봅시다.
    // ObservableExtensions.kt
    
    /**
     * Observable<T> を LiveData<T> に変換
     */
    fun <T> Observable<T>.toLiveData() : LiveData<T> {
    
        return object : MutableLiveData<T>() {
            var disposable : Disposable? = null;
    
            // ライフサイクルがActiveになったときに購読開始
            override fun onActive() {
                super.onActive()
    
                // Observable -> LiveData
                disposable = this@toLiveData.subscribe({
                    this.postValue(it)
                })
            }
    
            // ライフサイクルが非Activeになったら購読停止
            override fun onInactive() {
                disposable?.dispose();
                super.onInactive()
            }
        }
    }
    

    라이프사이클이 비액티브(구체적으로는 onPause)가 되었을 때에 구독 정지해 주면 반드시 괜찮을 것.

    다음과 같은 느낌으로 사용할 수 있습니다.
    // MainActivity.kt
    class MainActivity : AppCompatActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
    
            <いろいろ省略>
    
            // RxProperty を LiveData に変換。
            val liveDataUser = viewModel.user.toLiveData()
    
            // LiveData を購読
            liveDataUser.observe(lifecycleOwner, Observer { 
                editUserName.setTextKeepState(it)
            })
        }
    }
    

    보통은 RxProperty.value 그리고 DataBinding 하면 좋다고 생각합니다만, BindingAdapter 를 만드는 것이 번거롭거나 View측에서 조금 손질한 것을 하고 싶은 경우에는 .toLiveData() 로 LiveData 로 변환해, 안전 구독 관리를 즐길 수 있습니다.

    LiveData를 직접 사용하는 것이 더 좋은 경우



    RxProperty -> LiveData 할 때의 주의점으로서, 값이 변경시 밖에 통지되지 않는다, 라고 하는 것이 있습니다.
    어제 쓴 와 같이, LiveData 의 특성은, 동치 체크는 특별히 없고 값이 설정되면 (자) onChanged 로 설정해도 처음만 통지됩니다.

    그 때문에, Model->ViewModel->View의 방향으로, 값을 다만 흘러 흘려, View측에서 수신해 무엇인가 하고 싶은 경우는, LiveData 를 그대로 사용하는 것이 좋을 것입니다. 이것은 EventBus(Messenger)적인 사용법입니다.
    // MainViewModel.kt
    class MainViewModel : ViewModel() {
    
        // View 側から購読して Toast を表示するための LiveData。
        // 変更通知が必要ない(=EventBus的に使う)なら、LiveData をそのまま使うのがいいんじゃなイカ。
        private val _toast = MutableLiveData<String>()
        val toast : LiveData<String> = _toast
    
        fun showToast(view:View) {
            toast.set("トーストだよ")
        }
    }
    
    // MainActivity.kt
    class MainActivity : AppCompatActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
    
            <いろいろ省略>
    
            // Toast を表示するために、 toast:LiveData を購読する。
            viewModel.toast.observe(this, Observer { message ->
                Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
            })
        }
    }
    

    위의 예는 토스트를 표시하기 위해 RxJava 風に言うと distinctUntilChanged なので를 사용합니다.
    그 외에는 다이얼로그 박스의 표시나, 화면 천이의 요구 메세지를 View 측에 통지하기 위해서는 LiveData 를 그대로 사용하는 것이 좋다고 생각합니다 (라고 할까 거기를 Observable 로 할 필요를 느끼지 않는다).

    완성 시스템



    지난번 , 샘플로 GitHub의 리포지토리 목록을 검색하는 앱을 만들고 있었습니다.

    그것을,
  • DataBinding
  • LiveData
  • RxJava
  • RxProperty

  • 전부 사용해 써본 코드가 이쪽↓입니다.
  • amay077/LiveDataSample: ViewModel, DataBinding, LiveData, RxJava, RxProperty 전부 사용해본 샘플

  • 스크린샷은 이런 거야.



    AAC 시대에서도 Observable centric인 생각으로 좋지 않을까요.
    그림에 정리하면 이런 느낌입니다.



    RxProperty가 유행하지 않는 이유를 모르는 것입니다. 모두 사용해보십시오!

    좋은 웹페이지 즐겨찾기