根据第一个 LiveData 或 Flow 值组合 LiveData 或 Flow
Combine LiveData or Flow based on the first LiveData or Flow value
我想有条件地合并两个实时数据/流量值。这是我的问题:目前,我有两个实时数据/流量值。一个 LiveData 值始终发出 Status<Unit>
类型,而第二个 LiveData 值发出 T
类型。当第一个 LiveData 值发出 Status.Success
时,我手动将 View 设置为可见,现在知道第二个 LiveData 值将发出 T
.
我现在想要的是,在我的第一个 LiveData 值 onSucess
块
中获取第二个 Livedata 值 T
当前方法
class MyViewModel() : ViewModel() {
val myDownloadState: LiveData<Status<Unit>> = ...
val myDownloadData: LiveData<T> = ...
}
class MyFragment : Fragment() {
val myViewModel = ...
myViewModel.myDownloadState.observeStatus(
viewLifecycleOwner,
onSuccess = { it: Unit
binding.myRecyclerView.isVisible = true
},
onLoading = {
binding.myRecyclerView.isVisible = false
},
onError = { it: String?
toast(it.toString())
}
)
myViewModel.myDownloadData.observe(viewLifecycleOwner) { data: T
binding.myRecylerView.submitList(data)
}
}
我想要的
class MyViewModel() : ViewModel() {
val myCombinedState: LiveData<Status<T>> = ...
}
class MyFragment : Fragment() {
val myViewModel = ...
myViewModel.myCombinedState.observeStatus(
viewLifecycleOwner,
onSuccess = { it: T
binding.myRecyclerView.isVisible = true
binding.myRecylerView.submitList(data)
},
onLoading = {
binding.myRecyclerView.isVisible = false
},
onError = { it: String?
toast(it.toString())
}
)
}
这是两个实时数据值的来源:
interface IWorkerContract<T, R> {
// this is "myDownloadData"
val appDatabaseData: LiveData<R>
// this is "myDownloadState"
val workInfo: LiveData<Status<Unit>>
}
@Singleton
class DocumentWorkerContract @Inject constructor(
@ApplicationContext private val context: Context,
private val documentDao: DocumentDao,
) : IWorkerContract<Unit, List<DocumentCacheEntity>> {
// this is "myDownloadData"
override val appDatabaseData: LiveData<List<DocumentCacheEntity>>
get() = documentDao.getListLiveData()
// this is "myDownloadState"
override val workInfo: LiveData<Status<Unit>>
get() = WorkManager
.getInstance(context)
.getWorkInfoByIdLiveData(worker.id)
.mapToState()
}
状态Class
sealed class Status<out T> {
data class Success<out T>(val data: T) : Status<T>()
class Loading<out T>(val message: String? = null) : Status<T>()
data class Failure<out T>(val message: String?) : Status<T>()
companion object {
fun <T> success(data: T) = Success(data)
fun <T> loading(message: String? = null) = Loading<T>(message)
fun <T> failed(message: String?) = Failure<T>(message)
}
}
在这种情况下,我认为您应该尝试将 switchMap
与 map
结合使用。
这样试试:
class MyViewModel() : ViewModel() {
val myCombineState: LiveData<List<DocumentCacheEntity>> = myDownloadState.switchMap { state ->
myDownloadData.map { data ->
when (state) {
is Status.Success -> {
Status.Success(data)
}
is Status.Loading -> {
Status.Loading()
}
is Status.Error -> {
Status.Error()
}
}
}
}
}
我想有条件地合并两个实时数据/流量值。这是我的问题:目前,我有两个实时数据/流量值。一个 LiveData 值始终发出 Status<Unit>
类型,而第二个 LiveData 值发出 T
类型。当第一个 LiveData 值发出 Status.Success
时,我手动将 View 设置为可见,现在知道第二个 LiveData 值将发出 T
.
我现在想要的是,在我的第一个 LiveData 值 onSucess
块
T
当前方法
class MyViewModel() : ViewModel() {
val myDownloadState: LiveData<Status<Unit>> = ...
val myDownloadData: LiveData<T> = ...
}
class MyFragment : Fragment() {
val myViewModel = ...
myViewModel.myDownloadState.observeStatus(
viewLifecycleOwner,
onSuccess = { it: Unit
binding.myRecyclerView.isVisible = true
},
onLoading = {
binding.myRecyclerView.isVisible = false
},
onError = { it: String?
toast(it.toString())
}
)
myViewModel.myDownloadData.observe(viewLifecycleOwner) { data: T
binding.myRecylerView.submitList(data)
}
}
我想要的
class MyViewModel() : ViewModel() {
val myCombinedState: LiveData<Status<T>> = ...
}
class MyFragment : Fragment() {
val myViewModel = ...
myViewModel.myCombinedState.observeStatus(
viewLifecycleOwner,
onSuccess = { it: T
binding.myRecyclerView.isVisible = true
binding.myRecylerView.submitList(data)
},
onLoading = {
binding.myRecyclerView.isVisible = false
},
onError = { it: String?
toast(it.toString())
}
)
}
这是两个实时数据值的来源:
interface IWorkerContract<T, R> {
// this is "myDownloadData"
val appDatabaseData: LiveData<R>
// this is "myDownloadState"
val workInfo: LiveData<Status<Unit>>
}
@Singleton
class DocumentWorkerContract @Inject constructor(
@ApplicationContext private val context: Context,
private val documentDao: DocumentDao,
) : IWorkerContract<Unit, List<DocumentCacheEntity>> {
// this is "myDownloadData"
override val appDatabaseData: LiveData<List<DocumentCacheEntity>>
get() = documentDao.getListLiveData()
// this is "myDownloadState"
override val workInfo: LiveData<Status<Unit>>
get() = WorkManager
.getInstance(context)
.getWorkInfoByIdLiveData(worker.id)
.mapToState()
}
状态Class
sealed class Status<out T> {
data class Success<out T>(val data: T) : Status<T>()
class Loading<out T>(val message: String? = null) : Status<T>()
data class Failure<out T>(val message: String?) : Status<T>()
companion object {
fun <T> success(data: T) = Success(data)
fun <T> loading(message: String? = null) = Loading<T>(message)
fun <T> failed(message: String?) = Failure<T>(message)
}
}
在这种情况下,我认为您应该尝试将 switchMap
与 map
结合使用。
这样试试:
class MyViewModel() : ViewModel() {
val myCombineState: LiveData<List<DocumentCacheEntity>> = myDownloadState.switchMap { state ->
myDownloadData.map { data ->
when (state) {
is Status.Success -> {
Status.Success(data)
}
is Status.Loading -> {
Status.Loading()
}
is Status.Error -> {
Status.Error()
}
}
}
}
}