Immutable data holder

45fec3b965f9269bc8d6d2cf5bd93a13?s=47 haru067
February 28, 2019

Immutable data holder

45fec3b965f9269bc8d6d2cf5bd93a13?s=128

haru067

February 28, 2019
Tweet

Transcript

  1. Immutable data holder 2019/02/28 potatotips #59

  2. よくある話 タップしてユーザのプロフィールを表示 λοϓ

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

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

    = profileRepository.fetchProfile(userId) { profile.value = it } ProfileViewModel.kt
  5. 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>()
  6. 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>()
  7. 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>() ͳΜͱ͔͠ͳ͍ͱɾɾɾɾ
  8. 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>()
  9. 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>()
  10. 良さそう? まあよさそう。だが、、
 
 
 
 
 privateとはいえViewModel内なら書き換え可能 • ViewModelが肥大化したら多分事故る •

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

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

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

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

    profile: LiveData<Profile> = 
 Transformations.switchMap(_userId){ profileRepository.getProfile(it) }
  15. 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) }
  16. まとめ mutable、やめよう • 変数宣言 • オブジェクトが抱えるデータ 
 LiveDataならswitchMap(Transformations)
 を使うといい感じに

  17. 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 ΑΓ