鸿蒙系统的网络请求框架—蒹葭

目录:html

一、前言java

二、源码android

三、混淆git

四、添加依赖编程

五、具体用法json

六、总结设计模式

1、前言

蒹葭(JianJia)是一款鸿蒙系统上的网络请求框架,其实就是将安卓的Retrofit移植到鸿蒙系统上,我将鸿蒙版的Retrofit命名为蒹葭(JianJia)。蒹葭不只能实现Retrofit的功能,还会提供一些Retrofit没有的功能。Retrofit不支持动态替换域名,国内的应用通常都是有多个域名的,蒹葭支持动态替换域名。api

2、源码

源码
博客地址
要想读懂源码,须要具有如下技能。数组

  • 熟悉okhttp的常见用法 ;
  • 熟悉面向接口编程、反射、泛型、注解;
  • 熟悉构造者模式、适配器模式、工厂模式、策略模式、静态代理、动态代理、责任链模式等设计模式。

3、混淆

若是项目开启了混淆,请在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()
    }
}

四、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'

四、3 在配置文件中添加以下的权限

ohos.permission.INTERNET

5、具体用法,用法跟retrofit同样

蒹葭提供了一系列的注解,在进行网络请求的时候,就须要用到这些注解。
五、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()); } }); 

五、2 BaseUrl注解
国内的应用通常都是有多个域名的,BaseUrl注解能够对某个接口设置单独的域名。

public interface Wan {
 
    @BaseUrl("https://api.apiopen.top")
    @GET("getJoke")
    Call<ResponseBody> getJoke(@QueryMap Map<String, String> param); } 

五、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); } 

五、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 QueryMap注解
QueryMap注解以map的形式添加查询参数,被QueryMap注解修饰的参数类型必须是Map对象。

public interface Wan {
 
    @GET("wxarticle/list/405/1/json")
    Call<ResponseBody> search(@QueryMap Map<String, String> param); } 

五、6 SkipCallbackExecutor注解
在鸿蒙系统上,蒹葭默认会将服务端的响应回调到主线程,若是在方法上使用SkipCallbackExecutor注解,那就不会将服务端的结果回调到主线程。

public interface Wan {
    @SkipCallbackExecutor
    @GET("wxarticle/list/405/1/json")
    Call<ResponseBody> search(@QueryMap Map<String, String> param); } 

五、7 FormUrlEncoded注解和Field注解
FormUrlEncoded注解用于发送一个表单请求,使用该注解必须在方法的参数添加Field注解,被Field注解修饰的参数类型能够是数组、集合、字符串等。

public interface Wan {
    @POST("user/login")
    @FormUrlEncoded
    Call<ResponseBody> login(@Field("username") String username, @Field("password") String password); } 

五、8 FormUrlEncoded注解和FieldMap注解
有时候表单的参数会比较多,若是使用Field注解,方法的参数就会比较多,此时就可使用FieldMap注解,FieldMap注解以键值对的形式发送一个表单请求。若是被FieldMap注解修饰的参数不是Map类型,就会抛异常。若是Map的键值对为空,也会抛异常。

public interface Wan {
    @POST("user/login")
    @FormUrlEncoded
    Call<ResponseBody> login(@FieldMap Map<String, String> map); } 

五、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); } 

五、10 Url注解
Url注解用于添加接口的完整地址。在Retrofit里面,若是接口的域名与建立retrofit对象指定的域名不相同,那就会使用Url注解来解决问题。在蒹葭里面一样可使用Url注解来解决问题,但蒹葭还提供了BaseUrl来解决该问题。

public interface Wan {
 
    @GET()
    Call<ResponseBody> getArticle(@Url String url); } 

五、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); } 

五、12 Header注解
Header注解是做用于参数上的注解,用于添加请求头。

public interface Wan {
 
    @GET()
   Call<ResponseBody> foo(@Header("Accept-Language") String lang); } 

五、13 HeaderMap注解
HeaderMap注解是做用于参数上的注解,以map的形式添加请求头,map中每一项的键和值都不能为空,不然会抛异常。

public interface Wan {
 
    @GET("/search")
   Call<ResponseBody> list(@HeaderMap Map<String, String> headers); } 

五、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()); } }); 

6、总结

本文介绍了蒹葭的用法,蒹葭的原理跟retrofit是同样的,有兴趣的同窗能够去看下源码。

 

做者:裴云飞1

想了解更多内容,请访问51CTO和华为合做共建的鸿蒙社区:https://harmonyos.51cto.com

相关文章
相关标签/搜索