Kami membutuhkan LiveData pada tahun 2017. Pola Observer membuat hidup kami lebih mudah, tetapi opsi seperti RxJava terlalu rumit untuk pemula pada saat itu. Tim Komponen Arsitektur membuat LiveData: kelas penyimpanan data teramati yang sangat otoritatif yang dikembangkan untuk Android. Itu sederhana untuk membuatnya mudah untuk memulai, dan untuk kasus threading reaktif yang lebih kompleks disarankan untuk menggunakan RxJava, mengambil keuntungan dari integrasi antara keduanya.
Data Mati?
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". , . , .