NetWorkSdkKotlin 网络库kotlin版本

NetWorkSdkKotlin

目录

  • demo案例
  • 项目介绍
    • maven 配置
    • 依赖引入
    • 域名,intercept,factory配置
    • 解析服务器提供的json
    • 自定义BaseBean
    • 解析data里面的数据,统一错误处理,回传业务层成功与失败
    • 提供的请求方法(针对PHP不安规定返回错误的对象处理,比如我要对象,PHP给数组)
    • flow方式的拿到结果
    • 自定义Api
  • 站在巨人的肩膀上

以下介绍,只能讲个大概,建议跑Demo,我更多的希望各位开发者,可以自定义修改此库来。因为加密,解密,以及配置Content-Type各自需求不同。gitHub,喜欢再点个start

demo案例

 /*** @date 创建时间: 2023/7/25* @auther gxx* @description 发起网络请求**/fun readBanner(){viewModelScope.launch{val map = mutableMapOf<String,Any>()map["userId"] = "1"WanAndroidMAFRequest.getRequest("banner/json",map,object :DataParseSuFaCall<MutableList<Banner>>() {override fun onRequestDataSuccess(data: MutableList<Banner>?) {super.onRequestDataSuccess(data)if(BuildConfig.DEBUG){Log.d(TAG, "json = ${Gson().toJson(data)}");Log.d(TAG, "是否主线程 = ${Looper.getMainLooper() == Looper.myLooper()}");}}})}}

项目介绍

maven 配置
maven { url 'https://jitpack.io' }
依赖引入
dependencies {// Kotlinimplementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.1'implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.0'//okhttpimplementation 'com.squareup.okhttp3:okhttp:4.11.0'implementation 'com.squareup.okhttp3:logging-interceptor:4.11.0'// Retrofit 库build.gradle.ktsimplementation 'com.squareup.retrofit2:retrofit:2.9.0'implementation 'com.squareup.retrofit2:converter-gson:2.9.0'implementation 'com.google.code.gson:gson:2.9.0'// Kotlin 协程库implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2'implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2'implementation 'com.github.CMzhizhe:Retrofit-FlowCallAdapterFactory:v1.0.0'//如果自己不设计到加密,解密,可以加上下面这个implementation 'com.github.CMzhizhe:NetWorkSdkKotlin:v1.0.5'
}
域名,intercept,factory配置
object WanAndroidMAFRequest : OnBaseApiServiceListener {//配置域名val REQUEST_URL_FIRST = "https://www.wanandroid.com/"val mMobileRequest: MobileRequest = MobileRequest(this, ServiceDataTransform())val mOkHttpManager: OkHttpManager = OkHttpManager.Builder().setRequestUrl(REQUEST_URL_FIRST) //必选,如果默认端口是80 或者 443 就不用额外添加.setIsDebug(BuildConfig.DEBUG) //可选.setOnFactoryListener(FactoryImpl()) //可选,默认已配置GsonFactory  FlowFactory.setOnInterceptorListener(InterceptImpl())  //可选.build()//自定义错误factory的构建,后面会介绍这块配置val mErrorHandlerFactory = ErrorHandlerFactory().addErrorHandler(LoginErrorHandler()).addErrorHandler(PayErrorHandler()).addErrorHandler(TokenErrorHandler()).addErrorHandler(UnErrorHandler()).init()override fun onGetBaseApiService(): BaseApiService? {return mOkHttpManager.getApi(REQUEST_URL_FIRST,BaseApiService::class.java)}
}

这里有其他想说的,底层里面已经配置了GsonFactory、FlowFactory类型的转换。为啥我要说单独处理对于80或者443端口的呢,目的是为了有其他开发者直接修改此库,比如加密、解密的interceptor。域名A的加密/解密跟域名B的不同密匙不同,此时就需要开发者自己去根据域名获取密匙。以下是伪代码

class OkHttpManager {companion object{private val mCatchMapRetrofit = mutableMapOf<String, Retrofit>()//存储OkHttpManager,key为baseUrlprivate val mObj = Any()val mSecreKey = mutableMapOf<String, String>()//key为baseUrl,value为密匙 key类似=http://www.baidu.com/}
}
//加密
class EncryptionInterceptor : Interceptor {override fun intercept(chain: Interceptor.Chain): Response {val request = builder.build()val httpUrl = request.urlhttpUrl.host //www.baidu.comhttpUrl.port//9999httpUrl.scheme//http//http://www.baidu.com:9999/val port = HttpUrl.defaultPort(httpUrl.scheme)var url = ""if (port == 80 || port == 443) {url = "${httpUrl.scheme}://${httpUrl.host}/"} else {url = "${httpUrl.scheme}://${httpUrl.host}:${httpUrl.port}/"}val secreKey = OkHttpManager.mSecreKey[url]//TODO 加密return chain.proceed(builder.build())}
}
解析服务器提供的json

需要自己new 一个类,去实现 OnResponseBodyTransformJsonListener

class ServiceDataTransform : OnResponseBodyTransformJsonListener {companion object {const val ERROR_CODE = "errorCode"const val DATA = "data"const val ERROR_CODE_TYPE_0 = "0"//与服务器协商的正常状态const val ERROR_CODE_TYPE_101 = "101"//与服务器协商错误的逻辑const val ERROR_CODE_TYPE_102 = "102"//与服务器协商错误的逻辑const val ERROR_CODE_TYPE_103 = "103"//与服务器协商错误的逻辑}override fun onResponseBodyTransformJson(method: String,jsString: String): OnIParserListener {val baseBean: BaseBeanif (JsonParser.parseString(jsString).isJsonObject) {//服务器提供的是jsonObjectval jsonObject = JsonParser.parseString(jsString).asJsonObjectval errorCode = jsonObject.get(ERROR_CODE).asIntbaseBean = if (errorCode.toString() == ERROR_CODE_TYPE_0) {if (jsonObject.get(DATA).isJsonArray) {BaseBean(method, jsString, jsonObject.getAsJsonArray(DATA), errorCode)} else {BaseBean(method, jsString, jsonObject.getAsJsonObject(DATA), errorCode)}} else {//与服务器协商的异常逻辑// 可以在这里抛异常if (errorCode.toString() == ERROR_CODE_TYPE_101) {throw LoginApiException(errorCode.toString(), jsString, "登陆的异常")} else if (errorCode.toString() == ERROR_CODE_TYPE_102) {throw PayApiException(errorCode.toString(), jsString, "支付的异常")} else if (errorCode.toString() == ERROR_CODE_TYPE_103) {throw TokenApiException(errorCode.toString(), jsString, "token的异常")} else {throw UnApiException(errorCode.toString(), jsString, "未跟服务器定义的异常")}}} else {baseBean = BaseBean(method, jsString, null, -1)}return baseBean}
}

在这里,我有定义,我跟服务器之间的异常处理,这里进行异常抛出,在最终的onRequestFail拿到错误,丢给对应的Handler进行处理

自定义BaseBean

自己创建一个class文件去实现OnIParserListener接口

{errorCode:0data:{}msg:"ok"
}
class BaseBean( var resourceJsonString: String? = null,var jsonElement: JsonElement? = null,var errorCode:Int) : OnIParserListener {//这里是获取data里面的 JsonElementoverride fun resultDataJsonElement(): JsonElement? {return jsonElement}//这个是整个服务器提供的json格式override fun sourceJsonString(): String? {return resourceJsonString;}//这里是决定,是否服务器返回的正常数据override fun isSuccess(): Boolean {return errorCode == 0}
}
解析data里面的数据,统一错误处理,回传业务层成功与失败

我们在发起网络请求的时候是这样的,new DataParseSuFaCall 传递需要的具体格式

viewModelScope.launch{val map = mutableMapOf<String,Any>()map["userId"] = "1"WanAndroidMAFRequest.getRequest("banner/json",map,object :DataParseSuFaCall<MutableList<Banner>>() {override fun onRequestDataSuccess(data: MutableList<Banner>?) {//成功回调super.onRequestDataSuccess(data)}override fun onRequestBaseBeanFail(baseBean: BaseBean?) {//失败回调super.onRequestBaseBeanFail(baseBean)}})}/*** @date 创建时间: 2023/7/22* @auther gaoxiaoxiong* @description 服务器数据处理**/
open class DataParseSuFaCall<T> : AbsRequestResultImpl() {/*** @date 创建时间: 2023/7/23* @auther gaoxiaoxiong* @description 成功结果回调**/override fun onRequestSuccess(method: String,targetElement: JsonElement?,onIParserListener: OnIParserListener) {if (targetElement!=null){var result:Any?=nulltry {val parameterizedType = this::class.java.genericSuperclass as ParameterizedTypeval subType =  parameterizedType.actualTypeArguments.first() //获取泛型Tval adapter: JsonAdapter<Any> = MoshiUtil.moshi.adapter(subType)result = adapter.fromJson(targetElement.toString())} catch (e: Exception) {e.printStackTrace()//处理解析异常onRequestFail(e,"","解析异常", null,onIParserListener)}onRequestDataSuccess(if (result == null) null else result as T)onRequestBaseBeanSuccess(if (result == null) null else result as T,onIParserListener as BaseBean)}else{onRequestDataSuccess(null)onRequestBaseBeanSuccess(null, onIParserListener as BaseBean)}}/*** @date 创建时间: 2023/7/23* @auther gaoxiaoxiong* @description 失败接口的调用**/override fun onRequestFail(throwable: Throwable?,status: String?,failMsg: String?,errorJsonString: String?,onIParserListener: OnIParserListener?) {if (throwable!=null){val resPoneThrowable = WanAndroidMAFRequest.mErrorHandlerFactory.netWorkException(throwable)//自定义解析错误处理,这里是处理,你跟服务器之间定义好的错误信息if (resPoneThrowable.code == ExceptionHandle.ERROR.UNKNOWN.toString() && throwable is AbsApiException){
WanAndroidMAFRequest.mErrorHandlerFactory.rollGateError(WanAndroidMAFRequest.mErrorHandlerFactory.getErrorHandlers().first(),throwable)}}onRequestDataFail(status?:"", failMsg?:"", onIParserListener as BaseBean?)onRequestBaseBeanFail(onIParserListener as BaseBean? )}/*** @author gaoxiaoxiong* @date 创建时间: 2023/8/6/006* @description  请求失败**/open fun onRequestDataFail(code: String, msg: String, baseBean: BaseBean?=null) {}/*** @author gaoxiaoxiong* @date 创建时间: 2023/8/6/006* @description  请求失败**/open fun onRequestBaseBeanFail(baseBean: BaseBean?=null) {}/*** @author gaoxiaoxiong* @date 创建时间: 2023/8/6/006* @description  请求成功**/open fun onRequestDataSuccess(data: T?) {}/*** @author gaoxiaoxiong* @date 创建时间: 2023/8/6/006* @description  请求成功* 返回含有 BaseBean 的**/open fun onRequestBaseBeanSuccess(data: T?, baseBean: BaseBean) {}
}

这里再定义错误收集处理方法,比如我们登录错误了

/*** @date 创建时间: 2023/7/24* @auther gaoxiaoxiong* @description 登陆错误异常**/
class LoginApiException(code: String="", jsString: String="", errorMessage: String = "") :AbsApiException(code, jsString, errorMessage) {
}

既然错误了,那么就的要有对应的Handler处理这个错误

/*** @date 创建时间: 2023/7/24* @auther gaoxiaoxiong* @description 错误handler处理**/
class LoginErrorHandler(override var next: OnErrorHandler? = null) : OnErrorHandler {private val TAG = "LoginErrorHandler"override  fun handleError(error: AbsApiException): Boolean {if (error is LoginApiException){if(BuildConfig.DEBUG){Log.d(TAG, "${LoginErrorHandler::class.simpleName}已处理异常");}return true}else{return false}}
}//自定义错误factory的构建val mErrorHandlerFactory = ErrorHandlerFactory().addErrorHandler(LoginErrorHandler()).init()
提供的请求方法(针对PHP不安规定返回错误的对象处理,比如我要对象,PHP给数组)
  /*** @date 创建时间: 2023/7/22* @auther gaoxiaoxiong* @description get 请求**/suspend fun <T> getRequest(funName: String,urlMap: Map<String, Any> = mutableMapOf(),dataParseSuFaCall: DataParseSuFaCall<T>) {mMobileRequest.get(RqParamModel(baseUrl = REQUEST_URL_FIRST,funName = funName,null,urlMap = urlMap,emResultType = EmResultType.REQUEST_RESULT_OBJECT  //这里是定义你想要的类型的,默认是obj), dataParseSuFaCall, dataParseSuFaCall)}
flow方式的拿到结果

flow方式,其实原理也是通过接口方式拿到结果,然后通过callbackFlow拿到数据

/*** @author gaoxiaoxiong* @date 创建时间: 2023/8/6/006* @description  flow方式的调用**/suspend inline fun <reified T> createRequestFlow(funName: String) = callbackFlow<T> {val dataParseSuFaCall = object : DataParseSuFaCall<T>() {override fun onRequestDataSuccess(data: T?) {super.onRequestDataSuccess(data)trySend(data!!)}}mMobileRequest.get(RqParamModel(baseUrl = REQUEST_URL_FIRST,funName = funName,null,urlMap = mutableMapOf()), dataParseSuFaCall, dataParseSuFaCall)awaitClose { }}/*** @date 创建时间: 2023/7/25* @auther gxx* @description 发起网络请求**/fun readBanner(){viewModelScope.launch{WanAndroidMAFRequest.createRequestFlow<MutableList<Banner>>("banner/json").collect{//flow方式mBannerFlow.emit(Gson().toJson(it))}}}

自定义Api

    interface CustomApiService {//自定义接口名称@JvmSuppressWildcards@GETsuspend fun readBook(@Url url: String,@QueryMap urlMap: Map<String, Any>): ResponseBody}private val mJsonParseResult = JsonParseResult()//自定义api请求的Demosuspend fun <T> readBannerJson(dataParseSuFaCall: DataParseSuFaCall<T>) {val api = mOkHttpManager.getApi(REQUEST_URL_FIRST, CustomApiService::class.java)val url = "${REQUEST_URL_FIRST}banner/json"val responseBody = api?.readBook(url, mutableMapOf())mMobileRequest.responseBodyTransformJson(REQUEST_URL_FIRST,"banner/json",responseBody,dataParseSuFaCall).collect{if (it == null) {return@collect}mJsonParseResult.doIParseResult("${REQUEST_URL_FIRST}banner/json",EmResultType.REQUEST_RESULT_OWN,listener = it,dataParseSuFaCall,dataParseSuFaCall)}}
站在巨人的肩膀上

开发搭建网络请求框架 3这里借用了他的链式处理的思想,点赞点赞

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/28959.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

堡塔面板系统加固使用说明

更新日志&#xff1a; 宝塔系统加固5.0- 正式版 2023-08-07 1.加固php 配置文件 2.加固nginx 启动文件 宝塔系统加固4.1- 正式版 1、【修复】系统加固不会随系统启动自动开启的问题 2、【优化】大幅降低CPU使用率 宝塔系统加固4.0- 正式版 1、【增加】等保加固相关加固功能 2、…

高中教师能去美国做访问学者吗?

美国作为世界上高等教育水平较高的国家之一&#xff0c;吸引了众多学者前往交流学习。那么高中教师是否能够成为美国访问学者&#xff0c;这是当然的&#xff0c;高中老师是可以出国访学的&#xff0c;但是出国做访问学者会涉及到多方面的因素。 首先&#xff0c;教师个人的学术…

【torch.nn.Fold】和【torch.nn.Unfold】

文章目录 torch.nn.Unfold直观理解官方文档 toch.nn.Fold直观理解官方文档 torch.nn.Unfold 直观理解 torhc.nn.Unfold的功能&#xff1a; 从一个batch的样本中&#xff0c;提取出滑动的局部区域块patch&#xff08;也就是卷积操作中的提取kernel filter对应的滑动窗口&#…

Qt做警告处理界面

解决的问题&#xff1a; 做上位机时&#xff0c;多有检测仪器状态&#xff0c;事实显示警告&#xff0c;错误等状态&#xff0c;笔者就是需要显示各种仪器状态&#xff0c;做显示&#xff0c;后做出处理逻辑 Axure设计图&#xff1a; 需求&#xff1a;更新状态&#xff0c;根…

ValueError:The following settings are not supported :{‘username‘: ‘neo4j“}

py2neo版本不同所导致的问题&#xff0c;下面我通过一段代码说明该问题。 import py2neoif py2neo.__version__ 4.3.0:graph Graph(http://localhost:7474, username config.neo4j_username, password config.neo4j_password) elif py2neo.__version__ 2021.2.3:graph G…

国产密码算法

国密算法 总体介绍 国密即国家密码局认定的国产密码算法。主要有 SM1&#xff0c;SM2&#xff0c;SM3&#xff0c;SM4。密钥长度和分组长度均为 128 位。 SM1对称密码 SM1 算法是分组密码算法&#xff0c;分组长度为128位&#xff0c;密钥长度都为 128 比特&#xff0c;算法安…

flask-----信号

安装&#xff1a; flask中的信号使用的是一个第三方插件&#xff0c;叫做blinker。通过pip list看一下&#xff0c;如果没有安装&#xff0c;通过以下命令即可安装blinker&#xff1a; pip install blinker flask其中有内置的信号 template_rendered _signals.signal(temp…

命令模式(Command)

命令模式是一种行为设计模式&#xff0c;可将一个请求封装为一个对象&#xff0c;用不同的请求将方法参数化&#xff0c;从而实现延迟请求执行或将其放入队列中或记录请求日志&#xff0c;以及支持可撤销操作。其别名为动作(Action)模式或事务(Transaction)模式。 Command is …

直播平台的秘密武器:揭秘流行直播实时美颜SDK的背后技术

近年来&#xff0c;随着社交媒体和直播平台的崛起&#xff0c;实时美颜成为了许多用户在分享自己生活的过程中的一项重要需求。无论是个人的自拍照片&#xff0c;还是主播在直播中的形象展示&#xff0c;美颜效果都直接影响着观众的视觉感受。而支撑这种实时美颜效果背后的技术…

python sqlalchemy 动态设置表名__tablename__,一个model对应多个table

我们在上一篇中说明了&#xff0c;如何在.net core的efcore中动态设置表名。 本文讲述如何在sqlalchemy中动态设置表名&#xff0c;使多个table可以对应到一个model 表如下 code example from sqlalchemy import create_engine,Column,BigInteger,String from sqlalchemy.ext…

Pandaer的iPhone手机壳

哇塞&#xff0c;Pandaer的设计太棒了&#xff01;手机壳的花样多到让我眼花缭乱&#xff0c;好多系列设计都很有意思&#xff0c;让人有集齐的冲动。我最近入手了几个iPhone的手机壳&#xff0c;它有亮色和透明的款式&#xff0c;亮色的壳内部也是亮的&#xff0c;因为手机壳全…

数组相关练习

数组练习 将数组转化成字符串数组拷贝求数组元素的平均值查找数组中指定元素(顺序查找)二分查找冒泡排序数组逆序 将数组转化成字符串 import java.util.Arrays;public class Text1 {public static void main(String[] args) {int[] arr {5, 6, 4, 2};System.out.println(Arr…

学习gRPC (三)

测试gRPC例子 编写proto文件实现服务端代码实现客户端代码 通过gRPC 已经编译并且安装好之后&#xff0c;就可以在源码目录下找到example 文件夹下来试用gRPC 提供的例子。 在这里我使用VS2022来打开仓库目录下example/cpp/helloworld目录 编写proto文件 下面是我改写的exa…

gazebo 导入从blender导出的dae等文件

背景&#xff1a; gazebo 模型库里的模型在我需要完成的任务中不够用&#xff0c;还是得从 solidworks、3DMax, blender这种建模软件里面在手动画一些&#xff0c;或者去他们的库里面在挖一挖。 目录 1 blender 1-1 blender 相关links 1-2 install 2 gazebo导入模型 2-1 g…

LayUI之入门

目录 1.什么是layui 2.layui、easyui与bootstrap的对比 有趣的对比方式&#xff0c;嘿嘿嘿.... easyuijqueryhtml4&#xff08;用来做后台的管理界面&#xff09; 半老徐娘 bootstrapjqueryhtml5 美女 拜金 layui 清纯少女 2.1 layui和bootstrap对比&#xff08;这两个都属…

【EI复现】梯级水光互补系统最大化可消纳电量期望短期优化调度模型(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Multimodal Learning with Transformer: A Survey

Transformer多模态学习 Abstract1 INTRODUCTION2 BACKGROUND2.1 Multimodal Learning (MML)2.2 Transformers: a Brief History and Milestones2.3 Multimodal Big Data 3 TRANSFORMERS: A GEOMETRICALLY TOPOLOGICAL PERSPECTIVE3.1 Vanilla Transformer3.1.1 Input Tokenizat…

旷视科技AIoT软硬一体化走向深处,生态和大模型成为“两翼”?

齐奏AI交响曲的当下&#xff0c;赛道玩家各自精彩。其中&#xff0c;被称作AI四小龙的商汤科技、云从科技、依图科技、旷视科技已成长为业内标杆&#xff0c;并积极追赶新浪潮。无论是涌向二级市场还是布局最新风口大模型&#xff0c;AI四小龙谁都不甘其后。 以深耕AIoT软硬一…

C++:基于浅拷贝/深拷贝对模拟string类的一些优化

文章目录 string类和日期类浅拷贝/深拷贝对于上述代码的深拷贝写法正常版本和优化版本写时拷贝 string类和日期类 前面我们已经实现了string类和日期类&#xff0c;这两个类有没有想过它们有什么不同&#xff1f; 其实答案很明显&#xff0c;不同的地方在于string类中涉及到内…

黑马点评学习笔记2

黑马点评学习笔记 1.缓存穿透1.1 缓存穿透是什么&#xff1f;1.2缓存穿透的解决方案1.2.1 缓存空对象1.2.2 布隆过滤1.2.3 其他解决方案 2.缓存雪崩2.1 缓存雪崩是什么&#xff1f;2.2 缓存雪崩的解决方案 3.缓存击穿3.1缓存击穿是什么&#xff1f;3.2缓存击穿的解决方案3.2.1互…