【问题标题】:Handle no internet connection error of retrofit 2.6 with kotlin coroutines使用 kotlin 协程处理改造 2.6 的无互联网连接错误
【发布时间】:2019-11-04 21:32:51
【问题描述】:

我正在使用带有 kotlin 协程的改造 2.6 在不阻塞 UI 线程的情况下进行 API 调用,我得到了它的工作,但是当我关闭互联网连接时应用程序崩溃了。 logcat 错误是:E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-1

这是我的代码:

private fun handleIntent(slug: String) {
    val service = UtilityMethods.migrationTimeService()

    UtilityMethods.showView(loading_view)
    UtilityMethods.hideView(network_error_msg)

    CoroutineScope(Dispatchers.IO).launch {
        val res = service.getPostBySlug(slug)

            try {
                withContext(Dispatchers.Main) {

                    //Do something with response e.g show to the UI.
                    val post = res.body()!!.first()

                    UtilityMethods.hideView(loading_view)

                    val title = post.title?.rendered
                    val content = post.content?.rendered
                    val imageUrl = post.jetPackFeaturedMediaUrl

                    title_txtView.text = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
                        Html.fromHtml(title, Html.FROM_HTML_MODE_COMPACT).toString()
                    else
                        Html.fromHtml(title).toString()

                    content_txtView.loadData(content.toString(), "text/html", "UTF-8")

                    Picasso.get().load(imageUrl).fit().centerCrop().into(thumbnail_imgview)
                }

            } catch (e: HttpException) {
                UtilityMethods.showView(network_error_msg)
            } catch (e: Throwable) {
                Toast.makeText(this@PostContentActivity, "Ooops: Something else went wrong", Toast.LENGTH_LONG)
            }
    }
}

【问题讨论】:

    标签: android kotlin retrofit2 kotlin-coroutines


    【解决方案1】:

    我的代码可以运行了,新代码是:

    private fun handleIntent(slug: String) = GlobalScope.launch(Dispatchers.Main) {
        val service = UtilityMethods.migrationTimeService()
    
        UtilityMethods.showView(loading_view)
        UtilityMethods.hideView(network_error_msg)
    
        try {
            val res = withContext(Dispatchers.IO) {
                service.getPostBySlug(slug)
            }
    
            //Do something with response e.g show to the UI.
            val post = res.body()!!.first()
    
            UtilityMethods.hideView(loading_view)
    
            val title = post.title?.rendered
            val content = post.content?.rendered
            val imageUrl = post.jetPackFeaturedMediaUrl
    
            title_txtView.text = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
                Html.fromHtml(title, Html.FROM_HTML_MODE_COMPACT).toString()
            else
                Html.fromHtml(title).toString()
    
            content_txtView.loadData(content.toString(), "text/html", "UTF-8")
    
            Picasso.get().load(imageUrl).fit().centerCrop().into(thumbnail_imgview)
        }
        catch (e: HttpException) {
            Toast.makeText(this@PostContentActivity, "Exception ${e.message}", Toast.LENGTH_LONG).show()
        }catch (e: IOException) {
            UtilityMethods.hideView(loading_view)
            UtilityMethods.showView(network_error_msg)
        } catch (e: Throwable) {
            Toast.makeText(this@PostContentActivity, "Ooops: Something else went wrong ${e.message}", Toast.LENGTH_LONG).show()
        }
    }
    

    【讨论】:

    • 您好,请您解释一下您所做的更改。我也面临同样的问题,但不知道如何处理。
    • 我做的主要改变是整个方法在 GlobalScope.launch(Dispatchers.Main) 块中,这是 UI 线程,然后我切换到 IO 线程 withContext(Dispatchers.IO) 其中我是 API 调用。 Dispatchers.IO 本身位于一个 try 块中,该块将捕获到的异常抛出到 Dispatchers.Main 即 UI 线程
    【解决方案2】:

    而不是这个:

        CoroutineScope(Dispatchers.IO).launch {
        val res = service.getPostBySlug(slug)
    
            try {
                withContext(Dispatchers.Main) {
    

    试试这个:

        CoroutineScope(Dispatchers.Main).launch {
        val res = service.getPostBySlug(slug)
    
            withContext(Dispatchers.IO) {
                try {
    

    在 Dispatchers.IO 中包装你的“try and catch”块代码,而不是在你的 try 块中包装你的 Dispatchers.IO

    【讨论】:

    • 我已经尝试过了,但没有成功。而且我不能在 Dispatchers.Main 中使用“service.getPostBySlug(slug)”,因为它是一个 API 服务函数
    【解决方案3】:

    所以在查看堆栈跟踪时,我发现当网络不可用时会抛出 ConnectException

    这就是我在 kotlin 中的做法,它对我有用,

    suspend fun<T: Any> safeAPICall(call: suspend () -> Response<T>) : T{
    val response = try {
        call.invoke()
    }
    catch (e:java.lang.Exception){
        e.printStackTrace()
        val message = if( e is ConnectException) "Connection Error" else "Something went wrong. Please try again."
        throw IOException(ResponseError(message, 500).convertToJsonString())
    }
    
    
    // When connection is OK
    
    if(response.isSuccessful){
        return response.body()!!
    }else{
        val error = response.errorBody()?.string()
    
        error?.let{
            val message = JSONObject(it).optString("message", "Something went wrong")
            val responseError = ResponseError(message, response.code())
            throw IOException(responseError.convertToJsonString())
    
        }
        throw IOException(ResponseError("Something went wrong. Please try again.", 500).convertToJsonString())
    }
    }
    

    我使用的数据类

    data class ResponseError(val message:String, val errorCode:Int)
    

    用法:

    try {
          val response = safeAPICall {APIClient.planner.viewSites(view.context.authToken)}
     }
     catch (e:Exception){
        view.snack(e.message?.toModel<ResponseError>()?.message?: unspecified_error)
     }
    

    奖金:

     inline fun <reified T> JSONObject.toModel(): T? = this.run {
       try {
           Gson().fromJson<T>(this.toString(), T::class.java)
       }
       catch (e:java.lang.Exception){ e.printStackTrace(); null }
    }
    
    
    inline fun <reified T> String.toModel(): T? = this.run {
       try {
          JSONObject(this).toModel<T>()
        }
       catch (e:java.lang.Exception){  null }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-05-21
      • 2013-03-28
      • 1970-01-01
      • 2012-01-24
      • 1970-01-01
      • 2019-09-10
      • 1970-01-01
      • 2020-09-25
      • 1970-01-01
      相关资源
      最近更新 更多