【问题标题】:How to use coroutine scope to call web service and handle error kotlinkotlin如何使用协程范围调用web服务和处理错误
【发布时间】:2020-01-23 10:59:15
【问题描述】:

我使用 kotlin 开发了一个 android 应用程序。我使用 swagger 来获取我所有的 Web 服务。 如果存在,我想调用 Web 服务并使用 try/catch 处理错误。 经过一段时间的研究,关于如何使用这个 WS,我发现我应该使用协程和 Dispatchers,我使用 GlobalScope 如下:

         GlobalScope.launch(Dispatchers.Default) {
  val productsType = mobileApi.apiMobileProductTypeGetAllPost(params, 0, 50, "", "")
withContext(Dispatchers.Main) {
    viewProductType.loadAllTypeProduct(productsType)}

这是 loadAllTypeProduct 的代码:

override fun loadAllTypeProduct(data: Array<ProductTypeData>) {
        recyclerViewProductTypeList.apply {
            recyclerViewProductTypeList.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
            recyclerViewProductTypeList.adapter = ProductTypeItemAdapter(data, this@HomeFragment, context)
        }
    }

但是,我发现我应该使用 Coroutine Scope 而不是 Global Scope 并且 Global Scope 非常不受欢迎。 因此,我将代码从上面的代码更改为以下代码:

   val scope = CoroutineScope(Dispatchers.Main)
        basicViewInterface.showProgressBar()
        val task = scope.launch {
            try {
               withContext(Dispatchers.IO) {
                   val productsType=  mobileApi.apiMobileProductTypeGetAllPost(params, 0, 50, "", "")
                   viewProductType.loadAllTypeProduct(productsType)
                }
                basicViewInterface.hideProgressBar()
            } catch (e: Throwable) {
                e.printStackTrace()
            }
        }
        if (task.isCancelled){
            basicViewInterface.displayError("error")
        }

我想调用我的 WS 并使用 try/catch 处理异常并在 Toast 中显示错误,我该怎么做。

【问题讨论】:

    标签: android kotlin kotlin-coroutines


    【解决方案1】:

    协程作用域的要点在于,它在您检测到用户已经离开当前活动的地方可用,因此您可以在一个中心位置取消它并取消所有子协程。您的更改只是创建了一个本地的一次性范围,与使用 GlobalScope 一样糟糕。如果您的代码在 Activity 或 Fragment 中,则让该类实现 CoroutineScope by MainScope,您可以在 CoroutineScopedocumentation 中看到更详细的示例。

    至于处理异常,代码应该和你发布的差不多,只是注意切换上下文。协程作用域应指定 Main 作为调度程序,您应该切换到 IO 仅用于阻塞网络调用,如下所示:

    basicViewInterface.showProgressBar()
    scope.launch {
        try {
            val productsType = withContext(Dispatchers.IO) {
                mobileApi.apiMobileProductTypeGetAllPost(params, 0, 50, "", "")
            }
            viewProductType.loadAllTypeProduct(productsType)
            basicViewInterface.hideProgressBar()
        } catch (e: Throwable) {
            basicViewInterface.displayError("error")
        }
    }
    

    如果您将withContext 推入apiMobileProductTypeGetAllPost 的主体中会更好更干净,因为这是一个本地化的问题。从外部看,它应该只是另一个可以调用的可挂起函数,而无需担心给定实现是否阻塞非阻塞等低级细节。

    我注意到其他人提到协程异常处理程序,但我不建议使用它。它仅在协程层次结构的顶层起作用,其目的是仅捕获由于编程错误而在业务代码中未适当处理的异常。它相当于Java中的Thread.uncaughtExceptionHandler

    【讨论】:

    • 我想问你,当我调用几个 WS 并使用你的解决方案时,是否有办法让应用程序更快
    • 您可以随时启动并发协程并进行并发 WS 调用。
    【解决方案2】:

    如果您想自己处理异常,则需要使用CoroutineExceptionHandler

    文档指出:

    协程上下文中用于处理未捕获的可选元素 例外。

    通常,未捕获的异常只能由创建的协程产生 使用启动构建器。使用 async 创建的协程 总是捕获所有异常并在结果中表示它们 延迟对象。

    怎么样?创建此异常处理程序的对象,然后将其作为上下文传递给您的协程,如下所示:

    // Create object of exception handler
    val exceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable ->
        // Here you can handle your exception
    }
    
    val scope = CoroutineScope(Dispatchers.Main)
    basicViewInterface.showProgressBar()
    // pass exception handler as context to launch method
    val task = scope.launch(exceptionHandler) {
            withContext(Dispatchers.IO) {
                val productsType=  mobileApi.apiMobileProductTypeGetAllPost(params, 0, 50, "", "")
                viewProductType.loadAllTypeProduct(productsType)
            }
            basicViewInterface.hideProgressBar()
        }
    

    【讨论】:

    • 感谢您的回复,它也可以使用但我只是通过以下代码更改 productsType:val productsType = withContext(Dispatchers.IO) { mobileApi.apiMobileProductTypeGetAllPost(params, 0, 50, "" , "") }
    猜你喜欢
    • 2020-01-10
    • 1970-01-01
    • 2019-06-02
    • 2020-10-01
    • 2020-09-25
    • 2021-11-11
    • 2022-01-18
    • 2011-05-12
    • 1970-01-01
    相关资源
    最近更新 更多