【问题标题】:How do i get my retrofit to wait until its done before i start my recycler view在我开始我的回收站视图之前,我如何让我的改造等到它完成
【发布时间】:2021-12-15 03:56:12
【问题描述】:

我正在尝试让我的回收站视图等到我的改造功能完成。改造功能存储在视图模型中,而回收器视图在我的活动中。我可以让它延迟工作,但这似乎不是一个好方法。

        GlobalScope.launch {
        suspend {
val txt = findViewById<TextView>(R.id.textbox)
            viewModel.getStaff()


            delay(10000)
            withContext(Dispatchers.Main) {
                Log.d("coroutineScope", "#runs on ${Thread.currentThread().name}")
                createRV(viewModel.pictureList, viewModel.actorList, viewModel.characterList, viewModel.houseList)

            }
        }.invoke()

这是我的改造功能

suspend fun getStaff(){
    val retrofit = Retrofit.Builder()
        .baseUrl("http://hp-api.herokuapp.com/")
        .addConverterFactory(GsonConverterFactory.create())
        .build()
    val service = retrofit.create(HarryPotterApi::class.java)
    val call = service.staff()

    try {

        call.enqueue(object : Callback<Staff> {

            override fun onResponse(call: Call<Staff>, response: Response<Staff>) {

                if (response.code() == 200) {
                    val characterData = response.body()!!
             

                     pictureList.add(characterData[0].name)
                     actorList.add(characterData[0].name)
                    characterList.add(characterData[0].name)
                    houseList.add(characterData[0].name)
                }
            }
            override fun onFailure(call: Call<Staff>, t: Throwable) {

            }
        })}catch (e: IOException) {

        e.printStackTrace()
    }

}

【问题讨论】:

  • Retrofit 从2.6.0 开始支持协程。只需将您的staff() 函数挂起,然后您就可以同步使用它,从而使您的代码更加简单。
  • 你的意思是getStaff()。如果是这样,但它是灰色的,并且说它是多余的。
  • 不,我的意思是HarryPotterApi.staff()。我没有您的完整代码,但您可以将其设置为:suspend fun staff(): Staff,然后像这样使用它:val characterData = service.staff()。然后你就可以删除getStaff()里面60%的代码,同时解决等待结果的问题。
  • 好的,我在答案中添加了我的意思。请注意,这可能不是一个完整的示例。

标签: android kotlin retrofit


【解决方案1】:

我建议一个更好的方法。 而不是delay (10000),隐藏recyclerView并改用占位符视图

当你准备好显示 recyclerView 时:

withContext(Dispatchers.Main) {

placeholderView.visibility = View.GONE
recyclerView.visibility = View.VISIBLE

                Log.d("coroutineScope", "#runs on ${Thread.currentThread().name}")
                createRV(viewModel.pictureList, viewModel.actorList, viewModel.characterList, viewModel.houseList)

            }

【讨论】:

    【解决方案2】:

    Retrofit 自2.6.0 以来支持协程和挂起函数,因此您不必使用回调然后以某种方式将异步调用转换为可挂起(这也是可能的)。您可以使 HarryPotterApi.staff() 本身可暂停,它们使您的整个代码更加简单和同步,同时解决了等待 getStaff() 完成的问题。

    我没有你的完整代码,但我假设 HarryPotterApi.staff() 声明如下:

    fun staff(): Call<Staff>
    

    使其可暂停:

    suspend fun staff(): Staff
    

    然后同步使用:

    suspend fun getStaff(){
        val retrofit = Retrofit.Builder()
            .baseUrl("http://hp-api.herokuapp.com/")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
        val service = retrofit.create(HarryPotterApi::class.java)
    
        val characterData = service.staff()
        pictureList.add(characterData[0].name)
        actorList.add(characterData[0].name)
        characterList.add(characterData[0].name)
        houseList.add(characterData[0].name)
    }
    

    这可能不是一个完全有效的例子,但我希望你能明白。

    请注意,与您原来的解决方案不同,上面的service.staff() 将在请求失败时抛出异常(感谢@Tenfour04 指出这一点)。根据您的需要,您可以捕获它或将其传播到外部代码。忽略原始代码中的失败似乎不是一个好的解决方案,因为getStaff() 调用之后的代码使用了getStaff() 应该检索的数据。

    【讨论】:

    • 我几乎没有使用过 Retrofit,但我认为 Retrofit 挂起函数如果无法连接或检索响应会抛出异常,所以值得一提的是它应该被包裹在 try/catch或 runCatching,除非在调用堆栈的上层处理。它与Call.enqueue() 形成对比,后者不抛出并且只调用回调的onFailure 部分。
    • 好点。我假设抛出错误是一种期望的行为,因为getStaff() 后面的代码使用检索到的数据,因此继续没有太大意义。并且原始代码消耗了失败只是因为 OP 不确定如何将回调转换为同步。但你是对的,我不应该在没有解释的情况下改变行为。谢谢,已更新。 @Tenfour04
    猜你喜欢
    • 2012-06-15
    • 1970-01-01
    • 1970-01-01
    • 2015-03-02
    • 2023-02-07
    • 1970-01-01
    • 1970-01-01
    • 2019-04-10
    • 1970-01-01
    相关资源
    最近更新 更多