优雅使用Retrofit,在协程时代遨游安卓网络请求(三)上

简介: 优雅使用Retrofit,在协程时代遨游安卓网络请求(三)

前言:由于框架本身也在不断地迭代,因此文章中的部分代码可能存在更新或者过时,如果你想阅读源码或者查看代码的在项目中的实际使用方法,可以查看笔者目前在维护的compose项目:Spacecraft: 《Spacecraft - 我的安卓技术实践平台》-查看代码请进入develop分支 (gitee.com)

本篇内容主要为实现网络框架中与全局相关的逻辑。


网络异常转自然语言信息


  在上一节中,我们遗留了部分代码未提供,这里我们回顾一下


/**
 * 网络请求出现异常
 */
data class Exception<T>(val exception: Throwable) : Failure<T>() {
    //分析异常类型,返回自然语言错误信息
    val exceptionMessage:String by lazy {
        //TODO 下文讲解
    }
}

  这个自然语言的意思是:用户能直接阅读的错误信息,我们换个角度想一下,如果程序直接把网络超时异常SocketTimeoutException的信息抛出给用户,例如一个Toast,会发生什么事呢?可想而知用户会感到非常的困惑(前提是他不是一个程序员),因此需要将粗暴的程序错误堆栈信息转换成人可读的信息。

依然是废话不多说!上代码。


/**
 * 网络异常解析器
 */
interface HttpExceptionParser{
    /**
     * 将一个异常转化为自然语言报错
     */
    fun parse(throwable: Throwable?): String
    /**
     * 默认实现
     */
    companion object{
        val DEFAULT_PARSER= object : HttpExceptionParser {
            override fun parse(throwable: Throwable?): String {
                return when (throwable) {
                    is ConnectException, is SocketException, is HttpException, is UnknownHostException -> "网络连接失败"
                    is SSLHandshakeException -> "证书验证失败"
                    is JSONException, is ParseException, is JsonParseException -> "解析报文失败"
                    is SocketTimeoutException -> "连接超时"
                    is MsgException -> throwable.tip
                    else -> "未知错误"
                }
            }
        }
    }
}

  代码非常的简单,就是一个接口中包含了一个方法,将throwable转成字符串,然后接口中包含一个默认实现(这里可以改成你想要的)

  接下来,我们再实现一个Holder去持有Parser,让Holder实现Parser的方法(代理者模式),然后调用真正的parser去解析(你可以更换parser去实现你想要的自定义逻辑)


/**
 * 异常处理器持有者
 */
object HttpExceptionParserHolder:HttpExceptionParser {
    var parser=DEFAULT_PARSER
    override fun parse(throwable: Throwable?): String {
        return parser.parse(throwable)
    }
}

  这样,回到最初的代码,我们把Holder传入进去,完成逻辑闭环,用户就再也不会看到奇奇怪怪的网络异常报错了。


/**
 * 网络请求出现异常
 */
data class Exception<T>(val exception: Throwable) : Failure<T>() {
    val exceptionMessage: String by lazy {
        HttpExceptionParserHolder.parse(exception)
    }
}

NetworkResult拦截器


  在本网络框架的网络请求中,在服务器无异常且拿到服务器报文后,逻辑会执行到Success中去,但是有时候我们有这样的需求,报文中有个字段,例如Code,如果Code不为1,则说明业务报错,因此我们还需要进一步判断Code的值,否则会出现BUG。

  那么问题来了,我们如果实现全局逻辑而不是在具体的某个请求的Success中回调呢? 笔者参考过很多人的解决方案,大部分是对OKhttp的拦截器进行处理,即在okhttp拦截器中进行校验,但是这样有个缺陷是,你需要多执行一遍实体类型的转换(因为Retrofit层已经有一层),性能差而且存在代码维护的难度(因为存在两套实体类转换逻辑,okhttp和retrofit各一套),因此我们希望统一在Retrofit层面进行校验。

  让我们回到第一节的代码(第一节传送门:优雅使用Retrofit,在协程时代遨游安卓网络请求(一) - 掘金 (juejin.cn)

  在第一节中,笔者提供了一个将Retrofit的Response转成NetworkResult的扩展方法,我们的关键点就是这里。


fun <T> Response<T>.toNetworkResult(): NetworkResult<T> =
    //此处可以做全局转换
   try {
        if (isSuccessful) {
            toSuccessResult()
        } else {
            toServerErrorResult()
        }
    } catch (t: Throwable) {
        t.toExceptionResult()
    }

  这个方法的返回值是NetworkResult,因此可以返回Success,Failure中的任意一种,我们只需要在这里插入转换的逻辑,将部分Success的转成Failure即可(当然你可以实现任意的转换,甚至将错误转成正确都可以,非常的任性)。


那么如何实现的,废话不多说,直接上代码!


interface GlobalNetworkResultInterceptor {
    /**
     * 拦截网络请求,
     */
    fun <T> onIntercept(networkResult: NetworkResult<T>): NetworkResult<T> {
        return networkResult
    }
    //默认实现
    object DefaultGlobalNetworkResultInterceptor : GlobalNetworkResultInterceptor
}

 和异常解析器非常类似,也是一接口带着一个默认实现,方法就是将一个NetworkResult变成另外一个NetworkResult,默认就是不转。


相关文章
|
2月前
|
数据库 Android开发 开发者
构建高效Android应用:采用Kotlin协程优化网络请求处理
【2月更文挑战第30天】 在移动应用开发领域,网络请求的处理是影响用户体验的关键环节。针对Android平台,利用Kotlin协程能够极大提升异步任务处理的效率和简洁性。本文将探讨如何通过Kotlin协程优化Android应用中的网络请求处理流程,包括协程的基本概念、网络请求的异步执行以及错误处理等方面,旨在帮助开发者构建更加流畅和响应迅速的Android应用。
|
4月前
|
安全 API Android开发
Android网络和数据交互: 解释Retrofit库的作用。
Android网络和数据交互: 解释Retrofit库的作用。
41 0
|
4月前
|
Android开发 开发者
Android网络和数据交互: 请解释Android中的AsyncTask的作用。
Android网络和数据交互: 请解释Android中的AsyncTask的作用。
22 0
|
1月前
|
编解码 Android开发
Android获取设备各项信息(设备id、ip地址、设备名称、运行商、品牌、型号、分辨率、处理器、国家码、系统语言、网络类型、oaid、android版本、操作系统版本、mac地址、应用程序签名..)1
Android获取设备各项信息(设备id、ip地址、设备名称、运行商、品牌、型号、分辨率、处理器、国家码、系统语言、网络类型、oaid、android版本、操作系统版本、mac地址、应用程序签名..)
50 1
|
1月前
|
编解码 开发工具 Android开发
Android获取设备各项信息(设备id、ip地址、设备名称、运行商、品牌、型号、分辨率、处理器、国家码、系统语言、网络类型、oaid、android版本、操作系统版本、mac地址、应用程序签名..)2
Android获取设备各项信息(设备id、ip地址、设备名称、运行商、品牌、型号、分辨率、处理器、国家码、系统语言、网络类型、oaid、android版本、操作系统版本、mac地址、应用程序签名..)2
29 2
|
11天前
|
移动开发 Java Android开发
构建高效Android应用:采用Kotlin协程优化网络请求
【4月更文挑战第24天】 在移动开发领域,尤其是对于Android平台而言,网络请求是一个不可或缺的功能。然而,随着用户对应用响应速度和稳定性要求的不断提高,传统的异步处理方式如回调地狱和RxJava已逐渐显示出局限性。本文将探讨如何利用Kotlin协程来简化异步代码,提升网络请求的效率和可读性。我们将深入分析协程的原理,并通过一个实际案例展示如何在Android应用中集成和优化网络请求。
|
12天前
|
存储 应用服务中间件 网络安全
Android 网络链接稳定性测试解决方案
Android 网络链接稳定性测试解决方案
19 0
|
19天前
|
Android开发 开发者
Android网络和数据交互: 请解释Android中的AsyncTask的作用。
Android&#39;s AsyncTask simplifies asynchronous tasks for brief background work, bridging UI and worker threads. It involves execute() for starting tasks, doInBackground() for background execution, publishProgress() for progress updates, and onPostExecute() for returning results to the main thread.
11 0
|
19天前
|
网络协议 安全 API
Android网络和数据交互: 什么是HTTP和HTTPS?在Android中如何进行网络请求?
HTTP和HTTPS是网络数据传输协议,HTTP基于TCP/IP,简单快速,HTTPS则是加密的HTTP,确保数据安全。在Android中,过去常用HttpURLConnection和HttpClient,但HttpClient自Android 6.0起被移除。现在推荐使用支持TLS、流式上传下载、超时配置等特性的HttpsURLConnection进行网络请求。
11 0
|
27天前
|
JSON 安全 Java
Android网络部分-----网络数据请求、解析
Android网络部分-----网络数据请求、解析
Android网络部分-----网络数据请求、解析