Share
Embed
Transcript
63 slides
-
Observable Component1 Component2 class Component1( private val cmp2: Component2 )
{ "// ""... fun onDataLoaded(data: Data) { cmp2.setData(data) } } Component1 から Component2 へのデータを渡すシンプルな方法 -
Observable ViewModel Activity class MyViewModel( private val activity: Activity )
{ "// ""... fun onDataLoaded(data: Data) { activity.setData(data) } } ViewModel が Activity を持つと何が悪いでしょうか? -
Observable ViewModel Activity Activity ViewModel では ViewModel が Activity の参照を持つのではなく
Activity が ViewModel の参照を持つようにした場合は? -
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 }) } } 第二引数はオブザーバで、値が変更されたことを知ることができる -
Lifecycle-aware class MyActivity : Activity() { val viewModel: MyViewModel =
"//""... override fun onCreate(""...) { viewModel.myObservable.observe(this, Observer { data "-> title = data.title }) } } 第一引数でどのライフサイクル(LifecycleOwner)に合わせるか -
Lifecycle-aware class MyActivity : Activity() { val viewModel: MyViewModel =
"//""... override fun onCreate(""...) { viewModel.myObservable.observeForever { data "-> title = data.title } } } LiveData#observeForever ではアクティブかどうかは問わない テストで使うことが多い -
Transformations#map "// Transformations.java public static <X, Y> LiveData<Y> map( LiveData<X>
source, final Function<X, Y> mapFunction) { ""... } map で他の LiveData に変換することが可能 -
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()) } } 簡単なサンプル -
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 のデータがあるとします -
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 変数を用意 -
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 変数を更新 -
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 だけのデータを管理したい -
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 だけにする -
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()) } } 簡単なサンプルでした -
Transformations#switchMap Transformations#map で他の LiveData に変換することが可能 "// Transformations.java public static <X,
Y> LiveData<Y> switchMap( LiveData<X> source, final Function<X, LiveData<Y">> switchMapFunction) { ""... } -
Transformations#switchMap class MyViewModel : ViewModel() { val repositoryResult = Transformations.switchMap(userManager.user)
{ user "-> repository.getDataForUser(user) } } 簡単に描くとこういう書き方になります -
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 間で共有する -
2. LiveData を Activity 間で共有する エッジケースではあるもの の、Lollipop で導入された Activity Transisions
では 2つの Activity がアク ティブになることがある -
class MyViewModel(private val repo: AnimalRepository) : ViewModel() { var animals
= MutableLiveData<List<Animal">>() fun getAnimals() { animals = Transformations.switchMap(repo.getAnimals()) { it } } } オブザーバは新しいものが割り当てられたと判断できない 再登録が必要になるし、以前のものを解除していない 3. Transformation を初期化時以外でインスタンス化する -
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 を初期化時以外でインスタンス化する -
1. 大きいオブジェクトを Transformations で使う 2. LiveData を Activity 間で共有する 3.
Transformation を初期化時以外でインスタンス化する アンチパターン -
多くのオペレータやストリームが必要な場合は素直に RxJava を使いましょう UI に関するものやライフサイクルに関するものがない場合は 素直にコールバックを使うか、RxJava を使いましょう 複雑な処理(APIなど)を Promise のように繋げたいなら
Coroutines や RxJava を使いましょう + LiveData を使うべきではないパターン -
多くのオペレータやストリームが必要な場合は素直に RxJava を使いましょう UI に関するものやライフサイクルに関するものがない場合は 素直にコールバックを使うか、RxJava を使いましょう 複雑な処理(APIなど)を Promise のように繋げたいなら
Coroutines や RxJava を使いましょう + LiveData を使うべきではないパターン -
多くのオペレータやストリームが必要な場合は素直に RxJava を使いましょう UI に関するものやライフサイクルに関するものがない場合は 素直にコールバックを使うか、RxJava を使いましょう 複雑な処理(APIなど)を Promise のように繋げたいなら
Coroutines や RxJava を使いましょう + LiveData を使うべきではないパターン -
多くのオペレータやストリームが必要な場合は素直に RxJava を使いましょう UI に関するものやライフサイクルに関するものがない場合は 素直にコールバックを使うか、RxJava を使いましょう 複雑な処理(APIなど)を Promise のように繋げたいなら
Coroutines や RxJava を使いましょう + LiveData を使うべきではないパターン -
多くのオペレータやストリームが必要な場合は素直に RxJava を使いましょう UI に関するものやライフサイクルに関するものがない場合は 素直にコールバックを使うか、RxJava を使いましょう 複雑な処理(APIなど)を Promise のように繋げたいなら
Coroutines や RxJava を使いましょう + LiveData を使うべきではないパターン -
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