Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Immutable data holder

haru067
February 28, 2019

Immutable data holder

haru067

February 28, 2019
Tweet

More Decks by haru067

Other Decks in Technology

Transcript

  1. MVVMによる実装 • ユーザIDを引数としてViewModelがRepository からfetch • pro leはDataBindingを通じてViewに表示 fun load(userId: String)

    = profileRepository.fetchProfile(userId) { profile.value = it } ProfileViewModel.kt var profile = MutableLiveData<Profile>()
  2. MVVMによる実装 • ユーザIDを引数としてViewModelがRepository からfetch • pro leはDataBindingを通じてViewに表示 fun load(userId: String)

    = profileRepository.fetchProfile(userId) { profile.value = it } ProfileViewModel.kt var profile = MutableLiveData<Profile>()
  3. MVVMによる実装 • ユーザIDを引数としてViewModelがRepository からfetch • pro leはDataBindingを通じてViewに表示 fun load(userId: String)

    = profileRepository.fetchProfile(userId) { profile.value = it } ProfileViewModel.kt var profile = MutableLiveData<Profile>() ͳΜͱ͔͠ͳ͍ͱɾɾɾɾ
  4. Lv1: mutableな変数宣言をやめる 知らないうちにobserveできなくなってしまう val に書き換えでimmutableに var data = MutableLiveData<String>() data.observe(this,

    Observer { print(it) }) data.value = "hello" data = MutableLiveData() data.value = "world" // ͜͜͸observe͞Εͳ͍ var profile = MutableLiveData<Profile>() val profile = MutableLiveData<Profile>()
  5. Lv2: mutableなデータを公開しない 変数をvalにしてもオブジェクト自体はまだmutable   ViewがViewModelのデータを変更できてしまう
 外からはread onlyなデータだけが見える形にする val data =

    MutableLiveData<String>() data.value = "hello" data.value = "world" // いくらでも更新できる private val _profile: MutableLiveData<Profile>() val profile: LiveData<Profile> get() = _profile val profile = MutableLiveData<Profile>()
  6. 良さそう? まあよさそう。だが、、
 
 
 
 
 privateとはいえViewModel内なら書き換え可能 • ViewModelが肥大化したら多分事故る •

    そもそも2つも変数を宣言するのはくどい private val _profile: MutableLiveData<Profile>() val profile: LiveData<Profile> get() = _profile ProfileViewModel.kt
  7. Lv3: そもそもmutableにしない switchMapを使いimmutableな定義に 
private val _userId = MutableLiveData<String>() … val

    profile: LiveData<Profile> = 
 Transformations.switchMap(_userId){ profileRepository.getProfile(it) }
  8. Lv3: そもそもmutableにしない switchMapを使いimmutableな定義に 
private val _userId = MutableLiveData<String>() … val

    profile: LiveData<Profile> = 
 Transformations.switchMap(_userId){ profileRepository.getProfile(it) } userIdの変更を監視
  9. Lv3: そもそもmutableにしない switchMapを使いimmutableな定義に 
private val _userId = MutableLiveData<String>() … val

    profile: LiveData<Profile> = 
 Transformations.switchMap(_userId){ profileRepository.getProfile(it) } IDに変更があればfetch
  10. Lv3: そもそもmutableにしない switchMapを使いimmutableな定義に 
private val _userId = MutableLiveData<String>() … val

    profile: LiveData<Profile> = 
 Transformations.switchMap(_userId){ profileRepository.getProfile(it) }
  11. Lv3: そもそもmutableにしない switchMapを使いimmutableな定義に 
 • 「pro leはIDの更新以外を理由に変更できない」
 という制約をコード上で表現することができる • 「pro

    leはIDをトリガーとしてfetchした値」
 というデータのフローが明確になる private val _userId = MutableLiveData<String>() … val profile: LiveData<Profile> = 
 Transformations.switchMap(_userId){ profileRepository.getProfile(it) }
  12. Bonus: より簡潔に 拡張関数を活用すると良さそう(ktxにある?)
 
 
 Transformations.switchMap(_userId) { profileRepository.getProfile(it) } _userId.switchMap

    { profileRepository.getProfile(it) } fun <X, Y> LiveData<X>.switchMap(body: (X) -> LiveData<Y>): 
 LiveData<Y> { return Transformations.switchMap(this, body) } 長い シンプル https://github.com/google/iosched ͷ Extensions.kt ΑΓ