LiveData 2017 . , , RxJava, . Architecture Components LiveData: , Android. , , RxJava, .
DeadData?
LiveData - Java-, . , Kotlin Flows. Flows () , Kotlin, Jetbrains; , Compose, .
Flows , ViewModel. , Android, .
, Flows , , .
Flow: , —
LiveData : , Android. , , .
LiveData Flow:
#1:
, :
<!-- Copyright 2020 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
class MyViewModel {
private val _myUiState = MutableLiveData<Result<UiState>>(Result.Loading)
val myUiState: LiveData<Result<UiState>> = _myUiState
// Load data from a suspend fun and mutate state
init {
viewModelScope.launch {
val result = ...
_myUiState.value = result
}
}
}
, StateFlow:
class MyViewModel {
private val _myUiState = MutableStateFlow<Result<UiState>>(Result.Loading)
val myUiState: StateFlow<Result<UiState>> = _myUiState
// Load data from a suspend fun and mutate state
init {
viewModelScope.launch {
val result = ...
_myUiState.value = result
}
}
}
StateFlow — SharedFlow ( Flow), LiveData:
.
.
( ).
, .
StateFlow. , .
#2:
, .
LiveData liveData:
class MyViewModel(...) : ViewModel() {
val result: LiveData<Result<UiState>> = liveData {
emit(Result.Loading)
emit(repository.fetchItem())
}
}
, UI- - Result
, , Loading
, Success
Error
.
Flow , :
class MyViewModel(...) : ViewModel() {
val result: StateFlow<Result<UiState>> = flow {
emit(repository.fetchItem())
}.stateIn(
scope = viewModelScope,
started = WhileSubscribed(5000), // Or Lazily because it's a one-shot
initialValue = Result.Loading
)
}
stateIn
— Flow, StateFlow
. , .
#3:
, , ID , AuthManager
, Flow:
LiveData :
class MyViewModel(authManager..., repository...) : ViewModel() {
private val userId: LiveData<String?> =
authManager.observeUser().map { user -> user.id }.asLiveData()
val result: LiveData<Result<Item>> = userId.switchMap { newUserId ->
liveData { emit(repository.fetchItem(newUserId)) }
}
}
switchMap
— , , userId
.
, userId
LiveData, Flow LiveData.
class MyViewModel(authManager..., repository...) : ViewModel() {
private val userId: Flow<UserId> = authManager.observeUser().map { user -> user.id }
val result: LiveData<Result<Item>> = userId.mapLatest { newUserId ->
repository.fetchItem(newUserId)
}.asLiveData()
}
Flows :
class MyViewModel(authManager..., repository...) : ViewModel() {
private val userId: Flow<UserId> = authManager.observeUser().map { user -> user.id }
val result: StateFlow<Result<Item>> = userId.mapLatest { newUserId ->
repository.fetchItem(newUserId)
}.stateIn(
scope = viewModelScope,
started = WhileSubscribed(5000),
initialValue = Result.Loading
)
}
, , transformLatest
emit
:
val result = userId.transformLatest { newUserId ->
emit(Result.LoadingData)
emit(repository.fetchItem(newUserId))
}.stateIn(
scope = viewModelScope,
started = WhileSubscribed(5000),
initialValue = Result.LoadingUser // Note the different Loading states
)
#4:
. , , .
: fetchItem
observeItem
, Flow.
LiveData LiveData emitSource
:
class MyViewModel(authManager..., repository...) : ViewModel() {
private val userId: LiveData<String?> =
authManager.observeUser().map { user -> user.id }.asLiveData()
val result = userId.switchMap { newUserId ->
repository.observeItem(newUserId).asLiveData()
}
}
, , flatMapLatest LiveData:
class MyViewModel(authManager..., repository...) : ViewModel() {
private val userId: Flow<String?> =
authManager.observeUser().map { user -> user?.id }
val result: LiveData<Result<Item>> = userId.flatMapLatest { newUserId ->
repository.observeItem(newUserId)
}.asLiveData()
}
Flow , LiveData:
class MyViewModel(authManager..., repository...) : ViewModel() {
private val userId: Flow<String?> =
authManager.observeUser().map { user -> user?.id }
val result: StateFlow<Result<Item>> = userId.flatMapLatest { newUserId ->
repository.observeItem(newUserId)
}.stateIn(
scope = viewModelScope,
started = WhileSubscribed(5000),
initialValue = Result.LoadingUser
)
}
StateFlow , .
#5 : MediatorLiveData -> Flow.combine
MediatorLiveData ( LiveData) - , . MediatorLiveData:
val liveData1: LiveData<Int> = ...
val liveData2: LiveData<Int> = ...
val result = MediatorLiveData<Int>()
result.addSource(liveData1) { value ->
result.setValue(liveData1.value ?: 0 + (liveData2.value ?: 0))
}
result.addSource(liveData2) { value ->
result.setValue(liveData1.value ?: 0 + (liveData2.value ?: 0))
}
Flow :
val flow1: Flow<Int> = ...
val flow2: Flow<Int> = ...
val result = combine(flow1, flow2) { a, b -> a + b }
StateFlow ( stateIn)
stateIn
StateFlow, . -, :
val result: StateFlow<Result<UiState>> = someFlow
.stateIn(
scope = viewModelScope,
started = WhileSubscribed(5000),
initialValue = Result.Loading
)
, , 5- started
, .
StateIn
3 ( ):
@param scope the coroutine scope in which sharing is started.
@param started the strategy that controls when sharing is started and stopped.
@param initialValue the initial value of the state flow.
This value is also used when the state flow is reset using the [SharingStarted.WhileSubscribed] strategy with the `replayExpirationMillis` parameter.
started
3 :
Lazily
: , , , scope .
Eagerly
: , scope .
WhileSubscribed
: .
Lazily
Eagerly
. , , WhileSubscribed
, , .
WhileSubscribed
WhileSubscribed , . StateFlow, stateIn
, View, , ( ). , , , , .. , , .
WhileSubscribed
:
public fun WhileSubscribed(
stopTimeoutMillis: Long = 0,
replayExpirationMillis: Long = Long.MAX_VALUE
)
:
stopTimeoutMillis
( ) . ( ).
, , . — , .
liveData 5 , , . WhileSubscribed(5000)
:
class MyViewModel(...) : ViewModel() {
val result = userId.mapLatest { newUserId ->
repository.observeItem(newUserId)
}.stateIn(
scope = viewModelScope,
started = WhileSubscribed(5000),
initialValue = Result.Loading
)
}
:
, , , , .
, , , .
, , , .
replayExpirationMillis
— ( ) (shareIn
initialValue
stateIn
).Long.MAX_VALUE
( , ). .
StateFlow
, StateFlows ViewModel, . , , , .
, . :
Activity.lifecycleScope.launch
: .
Fragment.lifecycleScope.launch
: .
LaunchWhenStarted, launchWhenResumed...
launch, launchWhenX
, , lifecycleOwner
X, , lifecycleOwner
X. , , .
, , , View. , , .
, , StateFlow, ; API.
lifecycle.repeatOnLifecycle
( lifecycle-runtime-ktx 2.4.0-alpha01) , : , .
, :
onCreateView(...) { viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.lifecycle.repeatOnLifecycle(STARTED) { myViewModel.myUiState.collect { ... } } } }
, STARTED
, RESUMED
, STOPPED
. Android.
API repeatOnLifecycle
StateFlow .
: StateFlow, Data Binding,
launchWhenCreated
,repeatOnLifecycle
` , .
Data Binding Flows
asLiveData()
, . ,lifecycle-runtime-ktx 2.4.0
.
ViewModel :
, :
"Android Developer. Basic". , . , .