$30 off During Our Annual Pro Sale. View Details »
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Livedata Basics
Search
keijumt
May 31, 2019
Technology
0
92
Livedata Basics
keijumt
May 31, 2019
Tweet
Share
More Decks by keijumt
See All by keijumt
新規アプリのDarkTheme対応
keijumt
1
250
Firebase App Distribution と Github Actions でapkを配布する
keijumt
1
630
Other Decks in Technology
See All in Technology
モバイルゲーム開発におけるエージェント技術活用への試行錯誤 ~開発効率化へのアプローチの紹介と未来に向けた展望~
qualiarts
0
530
Bakuraku Engineering Team Deck
layerx
PRO
12
6.6k
Security Diaries of an Open Source IAM
ahus1
0
130
AWS Bedrock AgentCoreで作る 1on1支援AIエージェント 〜Memory × Evaluationsによる実践開発〜
yusukeshimizu
4
270
re:Invent2025 コンテナ系アップデート振り返り(+CloudWatchログのアップデート紹介)
masukawa
0
210
手動から自動へ、そしてその先へ
moritamasami
0
260
Modern Data Stack大好きマンが語るSnowflakeの魅力
sagara
0
300
乗りこなせAI駆動開発の波
eltociear
1
590
Claude Code はじめてガイド -1時間で学べるAI駆動開発の基本と実践-
oikon48
45
27k
小さな判断で育つ、大きな意思決定力 / 20251204 Takahiro Kinjo
shift_evolve
PRO
1
490
オープンデータの内製化から分かったGISデータを巡る行政の課題
naokim84
2
1.4k
Kiro Autonomous AgentとKiro Powers の紹介 / kiro-autonomous-agent-and-powers
tomoki10
0
160
Featured
See All Featured
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
61k
How to Think Like a Performance Engineer
csswizardry
28
2.3k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
12
1.3k
Rebuilding a faster, lazier Slack
samanthasiow
84
9.3k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
162
15k
Designing Experiences People Love
moore
143
24k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
9
1k
Build your cross-platform service in a week with App Engine
jlugia
234
18k
Scaling GitHub
holman
464
140k
How to Ace a Technical Interview
jacobian
280
24k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
1.8k
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
380
Transcript
LiveDataの基本 松本圭樹
LiveDataとは?
ライフサイクルと連動した監視が 可能なデータホルダーのクラス
Observerパターン + Lifecycle
なぜLiveDataを利用するか?
LiveDataを利用するメリット • メモリリークしない • Activityが非活性になったことによるクラッシュがなくなる • 常に最新のデータ • 構成の変更(画面回転など)の変更に適切に対処できる •
ライフサイクルのハンドリングから開放される
ライフサイクルと連動 • ライフサイクルがアクティブな時にのみ通知が送られる • ライフサイクルが終了するときにObserverが破棄される
ライフサイクルがアクティブとは?
Lifecycle.Stateが RESUMEDまたはSTARTED
Lifecycle.State • CREATED • DESTROYED • INITIALIZED • RESUMED •
STARTED
Launch onCreate onStart onResume onPause onStop onDestroy Lifecycle State INITIALIZED
CREATED STARTED RESUMED STARTED CREATED DESTROYED
Launch onCreate onStart onResume onPause onStop onDestroy Lifecycle State INITIALIZED
CREATED STARTED RESUMED STARTED CREATED DESTROYED ライフサイクルが アクティブ
Launch onCreate onStart onResume onPause onStop onDestroy Lifecycle State INITIALIZED
CREATED STARTED RESUMED STARTED CREATED DESTROYED ライフサイクルが インアクティブ
Launch onCreate onStart onResume onPause onStop onDestroy Lifecycle State INITIALIZED
CREATED STARTED RESUMED STARTED CREATED DESTROYED ライフサイクルが 破棄される
通常のObserverパターン Activity Subject 監視 変更 通知
LiveData Activity LiveData 監視 変更 通知 Activity
実際にLiveDataを利用
例 Activity ViewModel LiveData 監視 通知
ViewModel class MainViewModel { val name = MutableLiveData<String>() init {
name.value = "Hoge" } }
ViewModel class MainViewModel { val name = MutableLiveData<String>() init {
name.value = "Hoge" } }
ViewModel class MainViewModel { val name = MutableLiveData<String>() init {
name.value = "Hoge" } } nameを監視しているObserverに通知を送信
ViewModel class MainViewModel { val name = MutableLiveData<String>() init {
name.postValue("Hoge") } } UIスレッド以外から通知を送る場合はpostValueを利用
ViewModel class MainViewModel { val name = MutableLiveData<String>("Huga") init {
name.value = "Hoge" } } 初期値を入れたい場合は第一引数に
Activity class MainActivity : AppCompatActivity() { override fun onCreate( …
) { val viewModel = MainViewModel() viewModel.name.observe(this, Observer { name -> }) } }
Activity class MainActivity : AppCompatActivity() { override fun onCreate( …
) { val viewModel = MainViewModel() viewModel.name.observe(this, Observer { name -> }) } }
Activity class MainActivity : AppCompatActivity() { override fun onCreate( …
) { val viewModel = MainViewModel() viewModel.name.observe(this, Observer { name -> }) } }
Activity class MainActivity : AppCompatActivity() { override fun onCreate( …
) { val viewModel = MainViewModel() viewModel.name.observe(this, Observer { name -> }) } } 第一引数はどのライフサイクル(LifecycleOwner)に合わせるか
Activity class MainActivity : AppCompatActivity() { override fun onCreate( …
) { val viewModel = MainViewModel() viewModel.name.observe(this, Observer { name -> }) } } 第二引数はオブザーバ、通知を受けた時にここが呼ばれる
Transformations
Transformationsとは? • オブザーバに通知する前にLiveDataの値を変更したり、値を元に別のLiveData インスタンスに変換して返すことが可能
Transformations • map • switchMap
Transformations#map • オブザーバに通知する前にLiveDataの値を変更する
Transformations#map class MainViewModel( … ) { val animals = MutableLiveData<List<Animal>>()
val cats : LiveData<List<Animal>> = Transformations.map(animals) { animals -> animals.filter { it.type == Animal.Type.Cat } } init { animals.value = animalRepository.getAnimals() } }
Transformations#map class MainViewModel( … ) { val animals = MutableLiveData<List<Animal>>()
val cats : LiveData<List<Animal>> = Transformations.map(animals) { animals -> animals.filter { it.type == Animal.Type.Cat } } init { animals.value = animalRepository.getAnimals() } }
Transformations#map class MainViewModel( … ) { val animals = MutableLiveData<List<Animal>>()
val cats : LiveData<List<Animal>> = Transformations.map(animals) { animals -> animals.filter { it.type == Animal.Type.Cat } } init { animals.value = animalRepository.getAnimals() } }
Transformations#map class MainViewModel( … ) { val animals = MutableLiveData<List<Animal>>()
val cats : LiveData<List<Animal>> = Transformations.map(animals) { animals -> animals.filter { it.type == Animal.Type.Cat } } init { animals.value = animalRepository.getAnimals() } }
Transformations#map class MainViewModel( … ) { val animals = MutableLiveData<List<Animal>>()
val cats : LiveData<List<Animal>> = Transformations.map(animals) { animals -> animals.filter { it.type == Animal.Type.Cat } } init { animals.value = animalRepository.getAnimals() } } 監視するLiveDataを第一引数に設定
Transformations#map class MainViewModel( … ) { val animals = MutableLiveData<List<Animal>>()
val cats : LiveData<List<Animal>> = Transformations.map(animals) { animals -> animals.filter { it.type == Animal.Type.Cat } } init { animals.value = animalRepository.getAnimals() } } 受け取ったデータを整形して返却する
Transformations#switchMap • 値を元に別のLiveDataインスタンスに変換して返すことが可能
Transformations#switchMap class MainViewModel( … ) { val type = MutableLiveData<Animal.Type>()
val filterdAnimals : LiveData<List<Animal>> = Transformations.switchMap(type) { type -> animalRepository.getAnimalsByType(type) } init { animalType.value = Animal.Type.Cat } }
Transformations#switchMap class MainViewModel( … ) { val type = MutableLiveData<Animal.Type>()
val filterdAnimals : LiveData<List<Animal>> = Transformations.switchMap(type) { type -> animalRepository.getAnimalsByType(type) } init { animalType.value = Animal.Type.Cat } }
Transformations#switchMap class MainViewModel( … ) { val type = MutableLiveData<Animal.Type>()
val filterdAnimals : LiveData<List<Animal>> = Transformations.switchMap(type) { type -> animalRepository.getAnimalsByType(type) } init { animalType.value = Animal.Type.Cat } }
Transformations#switchMap class MainViewModel( … ) { val type = MutableLiveData<Animal.Type>()
val filterdAnimals : LiveData<List<Animal>> = Transformations.switchMap(type) { type -> animalRepository.getAnimalsByType(type) } init { animalType.value = Animal.Type.Cat } }
Transformations#switchMap class MainViewModel( … ) { val type = MutableLiveData<Animal.Type>()
val filterdAnimals : LiveData<List<Animal>> = Transformations.switchMap(type) { type -> animalRepository.getAnimalsByType(type) } init { animalType.value = Animal.Type.Cat } } getAnimalsByTypeの戻り値はLiveData<List<Animal>>
アンチパターン
ViewでLiveDataを保持する
ViewでLiveDataを保持する • Viewはデータ表示の役割はあるが、データ保持の役割はない • 通常はViewModelでLiveDataを保持する ◦ 画面回転などにも耐える
MutableLiveDataをViewに公開
MutableLiveDataをViewに公開 • ViewからViewModelのLiveDataを操作が可能になる
バッキングプロパティを利用 class MainViewModel { private val _name = MutableLiveData<String>() val
name: LiveData<String> = _name } 外部に公開するのはLiveData型のメンバ変数
FragmentでLiveDataを購読時、第 一引数でthisを渡す
なぜだめなのか? • Fragment#onDestroyが呼ばれることなく、複数回onCreateViewが呼ばれる可 能性がある ◦ 重複してObserverを登録することになる
viewLifecycleOwnerを使う class MainFragment : Fragment() { override fun onCreateView( …
): View { val viewModel = MainViewModel() viewModel.name.observe(viewLifecycleOwner, Observer { }) return ... } }
viewLifecycleOwnerを使う class MainFragment : Fragment() { override fun onCreateView( …
): View { val viewModel = MainViewModel() viewModel.name.observe(viewLifecycleOwner, Observer { }) return ... } }
Toastの表示や、Activity遷移など のイベントでMutableLiveDataを 利用する
Activityの再生成で挙動がおかしく なる
Activityの再生成
Activityの再生成 画面遷移を行うLiveDataから 通知を受ける
Activityの再生成 画面遷移を行うLiveDataから 通知を受ける 再び画面遷移を行う LiveData から通知を受ける
Activityの再生成 画面遷移を行うLiveDataから 通知を受ける 一度通知を受けたデータは通 知を受け取らない
SingleLiveEvent • 同じデータは通知を受けることのないLiveDataを作成する • https://github.com/googlesamples/android-architecture/blob/dev-todo-m vvm-live/todoapp/app/src/main/java/com/example/android/architecture/ blueprints/todoapp/SingleLiveEvent.java
Transformationsを初期化時以外 で利用する
Transformationsを初期化時以外で利用する class MainViewModel ( ... ){ var cats = MutableLiveData<List<Animal>>()
fun getFilterName() { cats = Transformations.map(animalRepository.getAnimals()) { } } } オブザーバは以前のものを解除していない
ありがとうございました