鸿蒙系统的网络请求框架—蒹葭
目录:
一、前言
蒹葭(JianJia)是一款鸿蒙系统上的网络请求框架,其实就是将安卓的Retrofit移植到鸿蒙系统上,我将鸿蒙版的Retrofit命名为蒹葭(JianJia)。蒹葭不仅能实现Retrofit的功能,还会提供一些Retrofit没有的功能。Retrofit不支持动态替换域名,国内的应用一般都是有多个域名的,蒹葭支持动态替换域名。
二、源码
- 熟悉okhttp的常见用法 ;
- 熟悉面向接口编程、反射、泛型、注解;
- 熟悉构造者模式、适配器模式、工厂模式、策略模式、静态代理、动态代理、责任链模式等设计模式。
三、混淆
如果项目开启了混淆,请在proguard-rules.pro
添加如下的代码。关于混淆,可以查看鸿蒙代码配置混淆
-renamesourcefileattribute SourceFile -keepattributes SourceFile,LineNumberTable -dontwarn javax.annotation.** -keepattributes Signature, InnerClasses, EnclosingMethod, Exceptions # 蒹葭 -dontwarn poetry.jianjia.** -keep class poetry.jianjia.** { *; } -keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations -keepclassmembers,allowshrinking,allowobfuscation interface * { @poetry.jianjia.http.* <methods>; } # OkHttp3 -dontwarn okhttp3.logging.** -keep class okhttp3.internal.**{*;} -dontwarn okio.** # gson -keep class sun.misc.Unsafe { *; } -keep class com.google.gson.stream.** { *; } -keepattributes *Annotation* -keepclassmembers class * implements java.io.Serializable { static final long serialVersionUID; private static final java.io.ObjectStreamField[] serialPersistentFields; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve(); } # 在我的示例代码中,com.poetry.jianjia.bean这个包下面的类实现了Serialized接口, # 实现了Serialized接口的类不能被混淆,请把com.poetry.jianjia.bean这个包名替换成你自己的包名 -keep class com.poetry.jianjia.bean.**{*;}
四、添加依赖
4、1 在项目根目录下的build.gradle
文件中添加mavenCentral()
仓库,打开项目根目录下的build.gradle
文件,在build.gradle
文件的repositories
闭包下面添加mavenCentral()
buildscript { repositories { // 添加maven中央仓库 mavenCentral() maven { url 'https://mirrors.huaweicloud.com/repository/maven/' } maven { url 'https://developer.huawei.com/repo/' } maven { url 'http://maven.aliyun.com/nexus/content/repositories/central/' } jcenter() } dependencies { classpath 'com.huawei.ohos:hap:2.4.2.5' classpath 'com.huawei.ohos:decctest:1.0.0.6' } } allprojects { repositories { // 添加maven中央仓库 mavenCentral() maven { url 'https://mirrors.huaweicloud.com/repository/maven/' } maven { url 'https://developer.huawei.com/repo/' } maven { url 'http://maven.aliyun.com/nexus/content/repositories/central/' } jcenter() } }
4、2 打开entry
目录下的build.gradle
文件中,在build.gradle
文件中的dependencies
闭包下添加下面的依赖
// 蒹葭的核心代码 implementation 'io.gitee.zhongte:jianjia:1.0.0' // 数据转换器,数据转换器使用gson来帮我们解析json,不需要我们手动解析json implementation 'io.gitee.zhongte:converter-gson:1.0.0' implementation "com.google.code.gson:gson:2.8.2" // 日志拦截器,通过日志拦截器可以看到请求头、请求体、响应头、响应体 implementation 'com.squareup.okhttp3:logging-interceptor:3.7.0'
4、3 在配置文件中添加如下的权限
ohos.permission.INTERNET
五、具体用法,用法跟retrofit一样
蒹葭提供了一系列的注解,在进行网络请求的时候,就需要用到这些注解。
5、1 GET注解
创建接口,在方法里面使用GET
注解,GET
注解用于标识这是一个GET
请求,方法的返回值是Call
对象,泛型是ResponseBody
,其实泛型也可以是具体的实体对象,这个后面再说。蒹葭如何完成网络请求?使用构造者模式创建jianjia
对象,baseUrl
就是域名,在创建jianjia
对象的时候就必须指定域名。调用create
方法来生成接口的实例,调用wan.getBanner().enqueue
来执行网络请求,请求成功就会回调onResponse
方法,请求失败就会回调onFailure
方法。
public interface Wan { @GET("banner/json") Call<ResponseBody> getBanner(); } JianJia jianJia = new JianJia.Builder() .baseUrl("https://www.wanandroid.com") .build(); Wan wan = jianJia.create(Wan.class); wan.getBanner().enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { try { String json = response.body().string(); } catch (IOException e) { e.printStackTrace(); } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { LogUtils.info("yunfei", t.getMessage()); } });
5、2 BaseUrl注解
国内的应用一般都是有多个域名的,BaseUrl
注解可以对某个接口设置单独的域名。
public interface Wan { @BaseUrl("https://api.apiopen.top") @GET("getJoke") Call<ResponseBody> getJoke(@QueryMap Map<String, String> param); }
5、3 Path注解
Path
注解在路径中替换指定的参数值,定义下面的方法。可以看到我们定义了一个getArticle
方法,方法接收一个page
参数,并且我们的@GET
注解中使用{page}
声明了访问路径,这里你可以把{page}
当做占位符,而实际运行中会通过@Path("page")
所标注的参数进行替换。
public interface Wan { @GET("article/list/{page}/json") Call<ResponseBody> getArticle(@Path("page") int page); }
5、4 Query注解
Query
注解用于给get
请求添加请求参数,被Query
注解修饰的参数类型可以是数组、集合、字符串等。
public interface Wan { @GET("wxarticle/list/405/1/json") Call<ResponseBody> search(@Query("k") String k); @GET("wxarticle/list/405/1/json") Call<ResponseBody> search(@Query("k") String... k); @GET("wxarticle/list/405/1/json") Call<ResponseBody> search(@Query("k") List<String> k); }
5、5 QueryMap注解
QueryMap
注解以map
的形式添加查询参数,被QueryMap
注解修饰的参数类型必须是Map对象。
public interface Wan { @GET("wxarticle/list/405/1/json") Call<ResponseBody> search(@QueryMap Map<String, String> param); }
5、6 SkipCallbackExecutor注解
在鸿蒙系统上,蒹葭默认会将服务端的响应回调到主线程,如果在方法上使用SkipCallbackExecutor
注解,那就不会将服务端的结果回调到主线程。
public interface Wan { @SkipCallbackExecutor @GET("wxarticle/list/405/1/json") Call<ResponseBody> search(@QueryMap Map<String, String> param); }
5、7 FormUrlEncoded注解和Field注解
FormUrlEncoded
注解用于发送一个表单请求,使用该注解必须在方法的参数添加Field
注解,被Field
注解修饰的参数类型可以是数组、集合、字符串等。
public interface Wan { @POST("user/login") @FormUrlEncoded Call<ResponseBody> login(@Field("username") String username, @Field("password") String password); }
5、8 FormUrlEncoded注解和FieldMap注解
有时候表单的参数会比较多,如果使用Field
注解,方法的参数就会比较多,此时就可以使用FieldMap
注解,FieldMap
注解以键值对的形式发送一个表单请求。如果被FieldMap
注解修饰的参数不是Map
类型,就会抛异常。如果Map
的键值对为空,也会抛异常。
public interface Wan { @POST("user/login") @FormUrlEncoded Call<ResponseBody> login(@FieldMap Map<String, String> map); }
5、9 Body注解
服务端会要求端上把json
字符串作为请求体发给服务端。此时就可以使用Body
注解定义的参数可以直接传入一个实体类,内部会把该实体序列化并将序列化后的结果直接作为请求体发送出去。
如果被Body
注解修饰的参数的类型是RequestBody
对象,那调用者可以不添加数据转换器,内部会使用默认的数据转换器。
如果被Body
注解修饰的参数的类型不是RequestBody
对象,是一个具体的实体类,那调用者需要自定义一个类,并且继承Converter.Factory
。
public interface Wan { /** * 被Body注解修饰的参数的类型是RequestBody对象,那调用者可以不添加数据转换器,内部会使用默认的数据转换器 * * @param body * @return */ @POST("user/register") Call<ResponseBody> register(@Body RequestBody body); /** * 被Body注解修饰的参数的类型不是RequestBody对象,是一个具体的实体类,那调用者需要自定义一个类,并且继承Converter.Factory * * @param user * @return */ @POST("user/register") Call<ResponseBody> register(@Body User user); }
5、10 Url注解
Url
注解用于添加接口的完整地址。在Retrofit
里面,如果接口的域名与创建retrofit
对象指定的域名不相同,那就会使用Url
注解来解决问题。在蒹葭里面同样可以使用Url
注解来解决问题,但蒹葭还提供了BaseUrl
来解决该问题。
public interface Wan { @GET() Call<ResponseBody> getArticle(@Url String url); }
5、11 Headers注解
Headers
注解是作用于方法上的注解,用于添加一个或多个请求头。
public interface Wan { @Headers("Cache-Control: max-age=640000") @GET("/") Call<ResponseBody> getArticle(@Url String url); @Headers({ "X-Foo: Bar", "X-Ping: Pong" }) @GET("/") Call<ResponseBody> getArticle(@Url String url); }
5、12 Header注解
Header
注解是作用于参数上的注解,用于添加请求头。
public interface Wan { @GET() Call<ResponseBody> foo(@Header("Accept-Language") String lang); }
5、13 HeaderMap注解
HeaderMap
注解是作用于参数上的注解,以map
的形式添加请求头,map
中每一项的键和值都不能为空,否则会抛异常。
public interface Wan { @GET("/search") Call<ResponseBody> list(@HeaderMap Map<String, String> headers); }
5、14 添加数据转换器
之前我们在接口里面定义方法的时候,方法的返回值时Call
对象,泛型是ResponseBody
。在这种情况下,服务端返回给端上的数据就会在ResponseBody
里面,端上需要手动解析json
,将json
解析成一个实体类。
其实,我们没必要手动解析json
,可以让gson
帮我们解析json
。蒹葭支持添加数据转换器,在创建对象的时候添加数据转换器,也就是把gson
添加进来。在onResponse
方法里面就可以直接得到实体类对象了,gson
帮我们把json
解析成了一个实体对象。
首先在build.gradle
文件添加数据转换器的依赖。
// 数据转换器,数据转换器使用gson来帮我们解析json,不需要我们手动解析json implementation 'io.gitee.zhongte:converter-gson:1.0.0' implementation "com.google.code.gson:gson:2.8.2"
在代码中使用数据转换器
public interface Wan { @GET("banner/json") Call<Banner> getBanner(); } JianJia jianJia = new JianJia.Builder() .baseUrl("https://www.wanandroid.com") .addConverterFactory(GsonConverterFactory.create()) .build(); Wan wan = jianJia.create(Wan.class); wan.getBanner().enqueue(new Callback<Banner>() { @Override public void onResponse(Call<Banner> call, Response<Banner> response) { try { if (response.isSuccessful()) { // json已经被解析成banner对象了 Banner banner = response.body(); } } catch (IOException e) { e.printStackTrace(); } } @Override public void onFailure(Call<Banner> call, Throwable t) { LogUtils.info("yunfei", t.getMessage()); } });
六、总结
本文介绍了蒹葭的用法,蒹葭的原理跟retrofit是一样的,有兴趣的同学可以去看下源码。
作者:裴云飞1
想了解更多内容,请访问51CTO和华为合作共建的鸿蒙社区:https://harmonyos.51cto.com

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
一文抽丝剥茧带你掌握复杂Gremlin查询的调试方法
摘要:Gremlin是图数据库查询使用最普遍的基础查询语言。Gremlin的图灵完备性,使其能够编写非常复杂的查询语句。对于复杂的问题,我们该如何编写一个复杂的查询?以及我们该如何理解已有的复杂查询?本文带你逐步抽丝剥茧,完成复杂查询的调试。 本文分享自华为云社区《复杂Gremlin查询的调试方法》,原文作者:Uncle_Tom。 1. Gremlin简介 Gremlin是Apache TinkerPop 框架下的图遍历语言。Gremlin是一种函数式数据流语言,可以使得用户使用简洁的方式表述复杂的属性图(property graph)的遍历或查询。每个Gremlin遍历由一系列步骤(可以存在嵌套)组成,每一步都在数据流(data stream)上执行一个原子操作。 Gremlin是一种用于描述属性图中行走的语言。图形遍历分两个步骤进行。 1.1. 遍历源(TraversalSource) 开始节点选择(Start node selection)。所有遍历都从数据库中选择一组节点开始,这些节点充当图中行走的起点。Gremlin中的遍历是从TraversalSource开始的。 Grap...
- 下一篇
鸿蒙代码配置混淆
目录: 1、前言 2、ProGuard 3、混淆指令 4、给鸿蒙项目配置混淆 5、给出一个常见的混淆配置 6、总结 一、前言 Java代码会被编译成字节码,字节码非常容易被反编译,一旦字节码被反编译,源码也就泄露了。为了很好的保护源代码,需要对编译好后的字节码文件进行混淆。代码经过混淆后,包体积会变小,并且源码都被处理过,进一步保障了应用的安全。本文将首先介绍混淆原理以及混淆命令,然后教大家如何在鸿蒙项目里面配置混淆。 二、ProGuard ProGuard就是用来混淆代码的,主要有以下4个功能。 压缩(Shrink):检测并移除代码中无用的类、字段、方法和特性。可以使用下面的指令关闭压缩 # 关闭压缩 -dontshrink 优化(Optimize):对字节码进行优化,移除无用的指令。可以使用下面的指令关闭优化 # 关闭优化 -dontoptimize -optimizationpasses n 表示proguard对代码进行迭代优化的次数 混淆(Obfuscate):使用a,b,c,d这样简短而无意义的名称,对类、字段和方法进行重命名。可以使用下面的指令关闭混淆 # ...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- MySQL8.0.19开启GTID主从同步CentOS8
- Hadoop3单机部署,实现最简伪集群
- CentOS7安装Docker,走上虚拟化容器引擎之路
- CentOS7,8上快速安装Gitea,搭建Git服务器
- CentOS8编译安装MySQL8.0.19
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Linux系统CentOS6、CentOS7手动修改IP地址