一、亮点介绍:
自从鸿蒙手机版公布以来,我就始终在做移植的工作,将安卓代码移植到鸿蒙零碎上。Retrofit是安卓零碎上一款优良的网络申请框架,鸿蒙零碎并没有相似的网络申请框架。于是,我决定实现一套鸿蒙版的Retrofit。
蒹葭(JianJia)是一款鸿蒙零碎上的网络申请框架,其实就是将安卓的Retrofit移植到鸿蒙零碎上,我将鸿蒙版的Retrofit命名为蒹葭(JianJia)。蒹葭不仅能实现Retrofit的性能,还会提供一些Retrofit没有的性能。Retrofit不反对动静替换域名,国内的利用个别都是有多个域名的,蒹葭反对动静替换域名。Retrofit并不可能间接增加拦截器,只能通过okhttp来增加拦截器,蒹葭会反对增加拦截器。
二、Demo编译及成果出现如下:
Demo演示视频戳此
注:文档附件在最上面
三、源码:
https://gitee.com/zhongte/JianJia
要想读懂源码,须要具备以下技能。
相熟okhttp的常见用法
相熟面向接口编程、反射、泛型、注解
相熟结构者模式、适配器模式、工厂模式、策略模式、动态代理、动静代理、责任链模式等设计模式
四、用法,用法跟Retrofit一样
蒹葭提供了一系列的注解,在进行网络申请的时候,就须要用到这些注解。
4.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()); }});
4.2 BaseUrl注解
国内的利用个别都是有多个域名的,BaseUrl注解能够对某个接口设置独自的域名。
public interface Wan { @BaseUrl("https://api.apiopen.top") @GET("getJoke") Call<ResponseBody> getJoke(@QueryMap Map<String, String> param); }
4.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.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);}
4.5 QueryMap注解
QueryMap注解以map的模式增加查问参数,被QueryMap注解润饰的参数类型必须是Map对象
public interface Wan { @GET("wxarticle/list/405/1/json") Call<ResponseBody> search(@QueryMap Map<String, String> param); }
4.6 SkipCallbackExecutor注解
在鸿蒙零碎下,默认会将服务端的响应回调到主线程,如果在办法上应用SkipCallbackExecutor注解,那就不会将服务端的后果回调到主线程
public interface Wan { @SkipCallbackExecutor @GET("wxarticle/list/405/1/json") Call<ResponseBody> search(@QueryMap Map<String, String> param); }
4.7 FormUrlEncoded注解和Field注解
FormUrlEncoded注解用于发送一个表单申请,应用该注解必须在办法的参数增加Field注解,被Field注解润饰的参数类型能够是数组、汇合、字符串等
public interface Wan { @POST("user/login") @FormUrlEncoded Call<ResponseBody> login(@Field("username") String username, @Field("password") String password); }
4.8 FormUrlEncoded注解和FieldMap注解
有时候表单的参数会比拟多,如果应用Field注解,办法的参数就会比拟多,此时就能够应用FieldMap注解,FieldMap注解以map的模式发送一个表单申请。如果被FieldMap注解润饰的参数不是Map类型,就会抛异样。如果Map的键值对为空,也会抛异样。
public interface Wan { @POST("user/login") @FormUrlEncoded Call<ResponseBody> login(@FieldMap Map<String, String> map); }
4.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);}
4.10 Url注解
Url注解用于增加接口的残缺地址。在Retrofit外面,如果接口的域名与创立retrofit对象指定的域名不雷同,那就会应用Url注解来解决问题。在蒹葭外面同样能够应用Url注解来解决问题,但蒹葭还提供了BaseUrl来解决该问题。
public interface Wan { @GET() Call<ResponseBody> getArticle(@Url String url); }
4.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); }
4.12 Header注解
Header注解是作用于参数上的注解,用于增加申请头
public interface Wan { @GET() Call<ResponseBody> foo(@Header("Accept-Language") String lang); }
4.13 HeaderMap注解
HeaderMap注解是作用于参数上的注解,以map的模式增加申请头,map中每一项的键和值都不能为空,否则会抛异样
public interface Wan { @GET("/search") Call<ResponseBody> list(@HeaderMap Map<String, String> headers); }
五、增加数据转换器
之前咱们在接口外面定义方法的时候,办法的返回值时Call对象,泛型是ResponseBody。在这种状况下,服务端返回给端上的数据就会在ResponseBody外面,端上须要手动解析json,将json解析成一个实体类。
其实,咱们没必要手动解析json,能够让gson帮咱们解析json。蒹葭反对增加数据转换器,在创建对象的时候增加数据转换器,也就是把gson增加进来。在onResponse办法外面就能够间接失去实体类对象了,gson帮咱们把json解析成了一个实体类。
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()) { Banner banner = response.body(); } } catch (IOException e) { e.printStackTrace(); } } @Override public void onFailure(Call<Banner> call, Throwable t) { LogUtils.info("yunfei", t.getMessage()); }});
六、蒹葭的后续工作
6、1 上传文件也须要应用注解,目前蒹葭还没有上传文件的注解,上传文件的注解正在开发当中。
6、2 蒹葭目前还不反对间接增加拦截器,后续会把拦截器的性能加上。
6、3 网络申请框架的二次封装,网络申请框架的二次封装该当隔离掉第三方网络框架,如果未来有更好的网络框架,或者公司要求应用公司自研的网络框架,那就能够很容易的替换掉之前的网络框架,而不须要大改特改。
6、4 因为疫情起因,我预计得在北京过年了,无奈回老家过年。所以能够趁放假的时候,给大家录视频。手把手的叫大家实现本人的网络框架,心愿可能帮忙大家了解蒹葭的实现原理。当然了,蒹葭的实现原理跟Retrofit的原理是截然不同的。自身蒹葭就是从Retrofit移植过去的,只不过蒹葭能够运行在鸿蒙零碎上。
原文链接:https://developer.huawei.com/consumer/cn/forum/topic/0204470884054220049?fid=0101303901040230869
原作者:义薄云天小关羽