【问题标题】:Coroutines RecyclerView API Call协程 RecyclerView API 调用
【发布时间】:2023-01-05 23:44:22
【问题描述】:

我用房间分页库与MVVM(模型-视图-视图模型)。

我想要得到的是一个 Retrofit CALL 来为每个人获取一些数据可见的Recycler View 中的项目,然后相应地更新视图。现在我所得到的只是实现分页库并相应地显示数据。

我能做的是获取 PagedList 并获取整个列表的数据并更新视图?我可以为列出的每个项目进行 API 调用吗?我们不希望用户等待很长时间才能看到可见项目的更新数据......


class AllPetsFragment : Fragment() {

private lateinit var binding : FragmentAllPetsfragmentBinding private lateinit var linearLayoutManager: LinearLayoutManager private lateinit var allPetsViewModel: MainActivityViewModel

override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View 


{
binding = FragmentAllPetsfragmentBinding.inflate(inflater, container, false)
val view : View = binding.root

allPetsViewModel = ViewModelProvider(requireActivity()).get(MainActivityViewModel::class.java)

binding.btnOpenAddPet.setOnClickListener{
    startActivity(Intent(activity, AddPetActivity::class.java))
}

val adapter = PetAdapter(requireContext(), ClickListener {
    allPetsViewModel.updateData(it)
    val action = AllPetsFragmentDirections.actionMainMap()
    Navigation.findNavController(view).navigate(action)
})
linearLayoutManager = LinearLayoutManager(requireContext())
binding.petsRecycler.layoutManager = linearLayoutManager
binding.petsRecycler.adapter = adapter

subscribeUi(adapter)

return view
}

private fun subscribeUi(adapter: PetAdapter) { allPetsViewModel.getDevicesLiveData().observe(viewLifecycleOwner, { names -> if (names != null){ adapter.submitList(names) }
})
} }

class PetAdapter(val context: Context, private val cl: ClickListener) : PagedListAdapter<Device, PetAdapter.PetViewHolder>(PersonDiffCallback()) {

override fun onBindViewHolder(holder: PetViewHolder, position: Int) { val device = getItem(position)

if (device == null) {
    holder.clear()
} else {
    holder.bind(device, cl.clickListener)
}

}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PetViewHolder { return PetViewHolder(LayoutInflater.from(context).inflate(R.layout.item_pet, parent, false)) }

class PetViewHolder(view: View) : RecyclerView.ViewHolder(view) {
var tvName: TextView = view.findViewById(R.id.petName)
var tvDistance: TextView = view.findViewById(R.id.totalDistance)
var txtBattery: TextView = view.findViewById(R.id.txtBattery)
var txtGeofence: TextView = view.findViewById(R.id.txtGeofence)


fun bind(device: Device, clickListener: (Device) -> Unit) {
    tvName.text = device.name

    itemView.setOnClickListener { clickListener(device) }
}

fun clear() {
    tvName.text = null
}
}}

我应该在这里做什么?如何为不同的 RecyclerView item 调用不同的 API?

谢谢!

【问题讨论】:

    标签: android api kotlin android-recyclerview retrofit


    【解决方案1】:

    检查现有的协程适配器

    在为现有 API 编写自己的包装器之前,请检查适配器或扩展函数是否适用于您的用例。现有的库带有用于常见类型的协程适配器。


    未来类型

    对于未来类型,有 Java 8 的 CompletableFuture 和 Guava 的 ListenableFuture 的集成。这不是一个详尽的列表,如果适合您未来类型的适配器已经存在,请在线搜索。

    // Awaits completion of CompletionStage without blocking a thread
    suspend fun <T> CompletionStage<T>.await(): T 
    // Awaits completion of ListenableFuture without blocking a thread
    suspend fun <T> ListenableFuture<T>.await(): T
    

    使用这些函数,您可以摆脱回调并暂停协程,直到未来的结果返回。


    反应流

    对于反应流库,有针对 RxJava、Java 9 API 和反应流库的集成。

    // Transforms the given reactive Publisher into Flow.
    fun <T : Any> Publisher<T>.asFlow(): Flow<T>
    

    这些函数将反应流转换为 Flow。


    Android 特定的 API

    对于 Jetpack 库或 Android 平台 API,请查看 Jetpack KTX 库列表。目前,超过 20 个库拥有 KTX 版本,创建了 Java API 的甜美地道版本,范围从 SharedPreferences 到 ViewModels、SQLite 甚至 Play Core。


    回调

    回调是一种非常常见的异步通信解决方案。事实上,我们在 Running tasks in background thread 指南中将它们用于 Java 编程语言解决方案。然而,它们也有一些缺点:这种设计导致嵌套的回调,最终导致难以理解的代码。此外,错误处理更加复杂,因为没有一种简单的方法来传播它们。

    在 Kotlin 中,您可以使用协程简化调用回调,但为此,您需要构建自己的适配器。


    构建自己的适配器

    如果您找不到适用于您的用例的适配器,通常可以直接编写自己的适配器。对于一次性异步调用,请使用 suspendCancellableCoroutine API。对于流数据,请使用 callbackFlow API。


    流数据

    相反,如果我们想接收定期的位置更新(使用 requestLocationUpdates 函数)每当用户的设备在现实世界中移动时,我们都需要使用 Flow 创建数据流。

    理想的 API 应该是这样的:

    fun FusedLocationProviderClient.locationFlow(): Flow<Location>
    

    转换基于流式回调蜜蜂对于 Flow,使用创建新流的 callbackFlow 流构建器。在 callbackFlow lambda 中,我们处于协程的上下文中,因此可以调用挂起函数。与流构建器不同,channelFlow 允许使用 offer 方法从不同的 CoroutineContext 或协程外部发出值。

    通常,使用 callbackFlow 的流适配器遵循以下三个通用步骤:

    1. 创建使用 offer 将元素添加到流中的回调。
    2. 注册回调。
    3. 等待消费者取消协程并注销 打回来。

      使用协程,我们可以摆脱那些在逻辑变得复杂时会很快使我们的代码变得不可读的回调。

      希望这对你有帮助!

      考虑创建协程适配器,使您的 API 或现有 API 简洁、可读和 Kotlin 惯用。首先检查适配器是否已经可用,如果不可用,请使用 suspendCancellableCoroutine 创建您自己的适配器用于一次性调用,使用 callbackFlow 用于流数据。

      要亲身体验这个主题,请查看Building a Kotlin extensions library codelab

    【讨论】:

      猜你喜欢
      • 2018-06-13
      • 2016-04-21
      • 2020-01-30
      • 2020-03-22
      • 1970-01-01
      • 2020-11-03
      • 1970-01-01
      • 1970-01-01
      • 2018-11-07
      相关资源
      最近更新 更多