Level Up with LiveData (JP)

Level Up with LiveData (JP)

Android Dev Summit 2018 報告会

6dd0483f1353a4a359e92633cfd65c64?s=128

Daichi Furiya (Wasabeef)

December 10, 2018
Tweet

Transcript

  1. 6.

    Observable Component1 Component2 class Component1( private val cmp2: Component2 )

    { "// ""... fun onDataLoaded(data: Data) { cmp2.setData(data) } } Component1 から Component2 へのデータを渡すシンプルな方法
  2. 7.

    Observable ViewModel Activity class MyViewModel( private val activity: Activity )

    { "// ""... fun onDataLoaded(data: Data) { activity.setData(data) } } ViewModel が Activity を持つと何が悪いでしょうか?
  3. 11.

    LiveData は Observable の一種 class MyViewModel : ViewModel() { val

    myObservable: LiveData<String> = "//""... } class MyActivity : Activity() { val viewModel: MyViewModel = "//""... override fun onCreate(""...) { viewModel.myObservable.observe(this, Observer { data "-> title = data.title }) } } 第二引数はオブザーバで、値が変更されたことを知ることができる
  4. 14.

    Lifecycle-aware class MyActivity : Activity() { val viewModel: MyViewModel =

    "//""... override fun onCreate(""...) { viewModel.myObservable.observe(this, Observer { data "-> title = data.title }) } } 第一引数でどのライフサイクル(LifecycleOwner)に合わせるか
  5. 16.

    Lifecycle-aware class MyActivity : Activity() { val viewModel: MyViewModel =

    "//""... override fun onCreate(""...) { viewModel.myObservable.observeForever { data "-> title = data.title } } } LiveData#observeForever ではアクティブかどうかは問わない テストで使うことが多い
  6. 32.

    Transformations#map "// Transformations.java public static <X, Y> LiveData<Y> map( LiveData<X>

    source, final Function<X, Y> mapFunction) { ""... } map で他の LiveData に変換することが可能
  7. 34.

    Transformations#map enum class Type { DOG, CAT, BIRD } data

    class Animal(val type: Type, val name: String) class AnimalRepository { fun getAnimals() = "//""... } class DogViewModel(private val repo: AnimalRepository) : ViewModel() { private val animals = MutableLiveData<List<Animal">>() val dogs: LiveData<List<Animal">> = Transformations.map(animals) { list "-> list.filter { animal "-> animal.type "== Type.DOG } } fun getAnimals() { animals.postValue(repo.getAnimals()) } } 簡単なサンプル
  8. 35.

    Transformations#map enum class Type { DOG, CAT, BIRD } data

    class Animal(val type: Type, val name: String) class AnimalRepository { fun getAnimals() = "//""... } class DogViewModel(private val repo: AnimalRepository) : ViewModel() { private val animals = MutableLiveData<List<Animal">>() val dogs: LiveData<List<Animal">> = Transformations.map(animals) { list "-> list.filter { animal "-> animal.type "== Type.DOG } } fun getAnimals() { animals.postValue(repo.getAnimals()) } } 例えば、データソースから取得できる Animal のデータがあるとします
  9. 36.

    Transformations#map enum class Type { DOG, CAT, BIRD } data

    class Animal(val type: Type, val name: String) class AnimalRepository { fun getAnimals() = "//""... } class DogViewModel(private val repo: AnimalRepository) : ViewModel() { private val animals = MutableLiveData<List<Animal">>() val dogs: LiveData<List<Animal">> = Transformations.map(animals) { list "-> list.filter { animal "-> animal.type "== Type.DOG } } fun getAnimals() { animals.postValue(repo.getAnimals()) } } AnimalRepository を扱う DataViewModel に animals 変数を用意
  10. 37.

    Transformations#map enum class Type { DOG, CAT, BIRD } data

    class Animal(val type: Type, val name: String) class AnimalRepository { fun getAnimals() = "//""... } class DogViewModel(private val repo: AnimalRepository) : ViewModel() { private val animals = MutableLiveData<List<Animal">>() val dogs: LiveData<List<Animal">> = Transformations.map(animals) { list "-> list.filter { animal "-> animal.type "== Type.DOG } } fun getAnimals() { animals.postValue(repo.getAnimals()) } } Repository を使ってデータを取得し、animals 変数を更新
  11. 38.

    Transformations#map enum class Type { DOG, CAT, BIRD } data

    class Animal(val type: Type, val name: String) class AnimalRepository { fun getAnimals() = "//""... } class DogViewModel(private val repo: AnimalRepository) : ViewModel() { private val animals = MutableLiveData<List<Animal">>() val dogs: LiveData<List<Animal">> = Transformations.map(animals) { list "-> list.filter { animal "-> animal.type "== Type.DOG } } fun getAnimals() { animals.postValue(repo.getAnimals()) } } animals から dog だけのデータを管理したい
  12. 39.

    Transformations#map enum class Type { DOG, CAT, BIRD } data

    class Animal(val type: Type, val name: String) class AnimalRepository { fun getAnimals() = "//""... } class DogViewModel(private val repo: AnimalRepository) : ViewModel() { private val animals = MutableLiveData<List<Animal">>() val dogs: LiveData<List<Animal">> = Transformations.map(animals) { list "-> list.filter { animal "-> animal.type "== Type.DOG } } fun getAnimals() { animals.postValue(repo.getAnimals()) } } Type によってフィルタリングし、DOG だけにする
  13. 40.

    Transformations#map enum class Type { DOG, CAT, BIRD } data

    class Animal(val type: Type, val name: String) class AnimalRepository { fun getAnimals() = "//""... } class DogViewModel(private val repo: AnimalRepository) : ViewModel() { private val animals = MutableLiveData<List<Animal">>() val dogs: LiveData<List<Animal">> = Transformations.map(animals) { list "-> list.filter { animal "-> animal.type "== Type.DOG } } fun getAnimals() { animals.postValue(repo.getAnimals()) } } 簡単なサンプルでした
  14. 45.

    Transformations#switchMap Transformations#map で他の LiveData に変換することが可能 "// Transformations.java public static <X,

    Y> LiveData<Y> switchMap( LiveData<X> source, final Function<X, LiveData<Y">> switchMapFunction) { ""... }
  15. 46.

    Transformations#switchMap class MyViewModel : ViewModel() { val repositoryResult = Transformations.switchMap(userManager.user)

    { user "-> repository.getDataForUser(user) } } 簡単に描くとこういう書き方になります
  16. 51.

    class SharedLiveDataSource(val dataSource: MyDataSource) { fun loadDataForUser(userId: String): LiveData<Long> {

    val result = MutableLiveData<Long>() result.value = dataSource.getOnlineTime(userId) return result } } これだけ見ると特に問題なさそう... 2. LiveData を Activity 間で共有する
  17. 54.

    class MyViewModel(private val repo: AnimalRepository) : ViewModel() { var animals

    = MutableLiveData<List<Animal">>() fun getAnimals() { animals = Transformations.switchMap(repo.getAnimals()) { it } } } オブザーバは新しいものが割り当てられたと判断できない 再登録が必要になるし、以前のものを解除していない 3. Transformation を初期化時以外でインスタンス化する
  18. 55.

    class DogViewModel(private val repo: AnimalRepository) : ViewModel() { private val

    animals = MutableLiveData<List<Animal">>() val dogs: LiveData<List<Animal">> = Transformations.map(animals) { list "-> list.filter { animal "-> animal.type "== Type.DOG } } fun getAnimals() { animals.postValue(repo.getAnimals()) } } LiveData を var で定義しないことが大事 3. Transformation を初期化時以外でインスタンス化する
  19. 56.

    1. 大きいオブジェクトを Transformations で使う 2. LiveData を Activity 間で共有する 3.

    Transformation を初期化時以外でインスタンス化する アンチパターン
  20. 62.

    Resources Talk sessions: 
 - https://www.youtube.com/playlist?list=PLWz5rJ2EKKc8WFYCR9esqGGY0vOZm2l6e Web pages: 
 -

    https://medium.com/androiddevelopers/search?q=livedata Photos: - https://unsplash.com - https://www.pexels.com - http://www.iconarchive.com - https://www.irasutoya.com