【问题标题】:What is the difference between emit and emitSource with LiveData ? ( as in REAL time USE-CASE )使用 LiveData 的 emit 和 emitSource 有什么区别? (如实时用例)
【发布时间】:2019-10-24 18:06:28
【问题描述】:

emit 接受 data 类,而 emitSource 接受 LiveData<T> ( T -> data )。考虑以下示例:- 我有两种类型的调用:-

suspend fun getData(): Data // returns directly data

还有另一个;

suspend fun getData(): LiveData<Data> // returns live data instead

对于第一种情况,我可以使用:-

liveData {
   emit(LOADING)
   emit(getData())
}

我的问题:使用上述方法可以解决我的问题,为什么我们还需要emitSource(liveData) 吗?

使用emitSource 方法的任何好的用例都会说明问题!

【问题讨论】:

  • 很可能与您希望使用 Transformations.switchMap 或 MediatorLiveData 的场景有关。

标签: android android-architecture-components android-livedata android-jetpack kotlin-coroutines


【解决方案1】:

正如你所说,我认为它不能解决你所说的问题,但我通常这样使用它:

如果我想在从远程获取新数据的同时从数据库向用户显示缓存数据,只发出它看起来像这样:

liveData{
    emit(db.getData())
    val latest = webService.getLatestData()
    db.insert(latest)
    emit(db.getData())
}

但是使用 emitSource 它看起来像这样:

liveData{
    emitSource(db.getData())
    val latest = webService.getLatestData()
    db.insert(latest)
}

liveData 已经有了源,不需要再次调用 emit。

【讨论】:

  • 我一时搞不明白,尤其是在 db 场景下,把这两个例子都放出来很容易理解!
  • 什么是 LiveData 来源
  • @lons LiveData 源意味着 livedata 在任何地方都能从中获得价值。在此示例中,源是 db。
【解决方案2】:

据我了解,emit(someValue) 类似于myData.value = someValue,而emitSource(someLiveValue) 类似于myData = someLiveValue。这意味着只要您想设置一个值一次,您就可以使用 emit,但是如果您想将您的实时数据连接到另一个实时数据值,您可以使用 emit 源。一个例子是从对房间的调用中发出实时数据(使用emitSource(someLiveData)),然后执行网络查询并发出错误(使用emit(someError))。

【讨论】:

    【解决方案3】:

    我发现了一个真实的用例,它描述了emitSource 的使用,而不是emit,我现在在生产中使用了很多次。 :D 用例:

    假设你有一些用户数据(User,其中有一些字段,如 userIduserName)由一些 ApiService 返回。

    User 模特:

    data class User(var userId: String, var userName: String)
    

    视图/活动需要 userName 来绘制 UI。而userId 用于进行另一个 API 调用,该调用返回UserData,如profileImageemailId

    UserData 模特:

    data class UserData(var profileImage: String, var emailId: String)
    

    这可以在内部使用emitSource 通过在ViewModel 中连接两个liveData 来实现,例如:

    UserliveData -

    val userLiveData: LiveData<User> = liveData {
       emit(service.getUser())
    }
    

    UserDataliveData -

    val userDataLiveData: LiveData<UserData> = liveData {
       emitSource(userLiveData.switchMap {
           liveData {
               emit(service.getUserData(it.userId))
           }
       })
    }
    

    因此,在活动/视图中,可以调用getUser()getUserData(userId) 将通过switchMap 在内部自动触发

    您无需手动通过传递 id 来调用getUserData(id)

    这是一个简单的例子,假设有一个依赖任务链需要一个接一个地执行,每个任务都在活动中被观察到。 emitSource进来handy

    【讨论】:

      【解决方案4】:

      使用 emitSource(),您不仅可以发出单个值,还可以将您的 LiveData 附加到另一个 LiveData 并开始从它发出。无论如何,每个 emit() 或 emitSource() 调用都会删除之前添加的源。

      var someData = liveData {
          val cachedData = dataRepository.getCachedData()
          emit(cachedData)
      
          val actualData = dataRepository.getData()
          emitSource(actualData)
      }
      

      正在观察 someData 对象的 Activity 将快速接收设备上的缓存数据并更新 UI。然后,LiveData 本身将负责发出网络请求并将缓存的数据替换为新的实时数据流,这最终将触发 Activity 观察者并使用更新的信息更新 UI。

      来源:Exploring new Coroutines and Lifecycle Architectural Components integration on Android

      【讨论】:

      • 但是当缓存数据发生变化时呢?接下来我们如何发出这些。
      【解决方案5】:

      我想分享一个示例,我们使用“emit”和“emitsource”从 UI -> View Model -> Repository

      进行通信

      我们使用 emit 向下游发送值的存储库层

      suspend fun fetchNews(): Flow<Result<List<Article>>> {
          val queryPath = QueryPath("tata", apikey = AppConstant.API_KEY)
          return flow {
              emit(
                  Result.success(
                      openNewsAPI.getResponse(
                          "everything",
                          queryPath.searchTitle,
                          queryPath.page,
                          queryPath.apikey
                      ).articles
                  )
              )
          }.catch { exception ->
              emit(Result.failure(RuntimeException(exception.message)));
          }
      }
      

      ViewModel 层我们使用 emitsource 将实时数据对象传递给 UI 以供订阅

      val loader = MutableLiveData<Boolean>()
      
      val newsListLiveData = liveData<Result<List<Article>>> {
          loader.postValue(true)
          emitSource(newRepo.fetchNews()
              .onEach {
                  loader.postValue(false)
              }
              .asLiveData())
      }
      

      UI 层 - 我们观察 emitsource 发出的实时数据

       viewModel.newsListLiveData.observe(viewLifecycleOwner, { result ->
              val listArticle = result.getOrNull()
              if (result.isSuccess && listArticle != null) {
                  setupList(binding.list, listArticle)
              } else {
                  Toast.makeText(
                      appContext,
                      result.exceptionOrNull()?.message + "Error",
                      Toast.LENGTH_LONG
                  ).show()
              }
          })
      

      我们在 viewModel 中将 Flow observable 转换为 LiveData

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-10-08
        • 1970-01-01
        • 1970-01-01
        • 2020-11-18
        • 2011-02-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多