简体   繁体   English

根据第一个 LiveData 或 Flow 值组合 LiveData 或 Flow

[英]Combine LiveData or Flow based on the first LiveData or Flow value

I would like to combine two livedata / flow values conditionally.我想有条件地组合两个实时数据/流量值。 Here is my problem: Currently, I have two livedata / flow values.这是我的问题:目前,我有两个实时数据/流量值。 One LiveData value always emits type Status<Unit> while the second LiveData value emits T .一个 LiveData 值始终发出Status<Unit>类型,而第二个 LiveData 值发出T When the first LiveData value emits Status.Success I manually set View to visible and now know that the second LiveData value will emit T .当第一个 LiveData 值发出Status.Success时,我手动将 View 设置为可见,现在知道第二个 LiveData 值将发出T

What I now want is, to get the second Livedata value T inside my first LiveData value onSucess block我现在想要的是,在我的第一个 LiveData 值onSucess块中获取第二个 Livedata 值T

Current approach目前的做法

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)
   }

}

What I want我想要的是

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())
       }
   )
}

Here is where the two livedata values are coming from:这是两个 livedata 值的来源:

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()
}

State Class State 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)
    }
}

I think you should try using switchMap in combination with map in this case.在这种情况下,我认为您应该尝试将switchMapmap结合使用。

Try it this way:试试这样:

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()  
                }
            }
        }
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM