繁体   English   中英

kotlin如何使用协程作用域调用web服务并处理错误

[英]How to use coroutine scope to call web service and handle error kotlin

我使用 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 中显示错误,我该怎么做。

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

至于处理异常,代码应该看起来和你发布的差不多,只需要注意切换上下文。 协程范围应该将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

如果你想自己处理异常,那么你需要使用CoroutineExceptionHandler

文档指出:

协程上下文中的可选元素,用于处理未捕获的异常。

通常,未捕获的异常只能由使用启动构建器创建的协程产生。 使用 async 创建的协程始终捕获其所有异常并在生成的 Deferred 对象中表示它们。

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

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

暂无
暂无

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

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