RxJava+Retrofit+OkHttp 网络框架封装(一)

作者 : 开心源码 本文共8430个字,预计阅读时间需要22分钟 发布时间: 2022-05-12 共193人阅读
  • 前言
    春节过后是找工作的高峰期,我也不例外想找一个比较是自己满意的工作。在面试了几家公司每家居然都问RxJava,Retrofit,OkHttp的实现原理,趁离任期间还是把这个好好总结下。就先对他们做下简单的详情。
    RxJava+Retrofit+OkHttp 网络框架封装(一)
    RxJava+Retrofit+OkHttp 网络框架封装(二)
首先简单详情Retrofit、OKHttp和RxJava之间的关系:
  • Retrofit:Retrofit是Square公司开发的一款针对Android 网络请求的框架(底层默认是基于OkHttp 实现)。
  • OkHttp:也是Square公司的一款开源的网络请求库。
  • RxJava :”a library for composing asynchronous and event-based programs using observable sequences for the Java VM”(一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库)。RxJava使异步操作变得非常简单。

各自职责:Retrofit 负责 请求的数据 和 请求的结果,使用 接口的方式 呈现,OkHttp 负责请求的过程,RxJava 负责异步,各种线程之间的切换。

Retrofit 创立过程和参数的讲解

一、引入Retrofit的包,在build.gradle文件中增加如下配置:
  • 在这里我们先理解一下Android的项目架构,便于不熟习Android项目架构的读者加以理解:
    对于一个Android工程而言,有两个Gradle配置文件,一类是项目的Gradle配置,一类是工程的Gradle配置。每个项目(或者称为板块)都有属于自己Gradle配置,整个工程有一个通用的Gradle配置。
    1)、项目中的Gradle配置主要管理项目的属性和依赖;
    2)、工程中的Gradle配置主要用于管理一律项目的通用属性和工程的建构,如工程构建脚本(buildscript),库的下载地址(jcenter)等。

  • 工程中最基本的Gradle配置分为三部分,即 buildscript、allprojects、task clean。
    1) buildscript 表示构建脚本,依赖库来源于 Jcenter,依赖于Gradle的Build Tools 工具包;
    2) allprojects 表示一律项目的通用配置,依赖库的来源于 Jcenter;
    3) task clean 表示清理命令(gradle clean)脚本,删除工程根目录的build文件。

  • 当开发小的工程时, 开发人员很少会修改工程的Gradle配置,而是更关注项目的Gradle配置。在Gradle中,一个重要的部分就是增加第三方的依赖(dependencies)。使用第三方库,可以避免重复创立轮子,加快开发速度,提升代码的稳固性。

compile 'com.squareup.retrofit2:retrofit:2.3.0'//导入retrofitcompile 'com.google.code.gson:gson:2.6.2'//Gson 库//下面两个是RxJava 和 RxAndroidcompile 'io.reactivex.rxjava2:rxandroid:2.0.2'compile 'io.reactivex.rxjava2:rxjava:2.x.y'compile 'com.squareup.retrofit2:converter-gson:2.3.0'//转换器,请求结果转换成Modelcompile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'//配合Rxjava 使用
二、定义数据Bean结构
public class DataChildBean{    private String source;    private String unit;    public String getSource() {        return source;    }    public void setSource(String source) {        this.source = source;    }    public String getUnit() {        return unit;    }    public void setUnit(String unit) {        this.unit = unit;    }}
三、设计api接口

使用 POST,GET 请求方式时,只要要更改方法定义的标签,用 @POST ,@GET标签,参数标签用 @Field 或者者 @Body 或者者@ FieldMap

public interface MovieService {//比值标题栏列表@GET("rest/startFigure/tradingHelper")Call<DataChildBean> getMeasureQuotations(@Query("start") int start , @Query("count") int count);@FormUrlEncoded@POST("rest/measure/getLast")Call<DataChildBean> getMeasureInstruction(@Field("start") int start , @Field("count") int count);@POST("rest/options/exerviseprice") Call<BaseModel<ArrayList<String>>> getExervisePrice(@Body RequestBody body);}

网络请求方法和网络请求参数标签的讲解

  • 网络请求方法
    1、@HTTP
    作用:替换@GET、@POST、@PUT、@DELETE、@HEAD注解的作用 及 更多功能拓展
    具体使用:通过属性method、path、hasBody进行设置
public interface MovieService {    /**     * method:网络请求的方法(区分大小写)     * path:网络请求地址路径     * hasBody:能否有请求体     */    @HTTP(method = "GET", path = "blog/{id}", hasBody = false)    Call<ResponseBody> getCall(@Path("id") int id);    // {id} 表示是一个变量    // Call 接受返回对象    // method 的值 retrofit 不会做解决,所以要自行保证精确}

2、@GET、@POST 这里就不详情了

  • 标记类

1、@FormUrlEncoded
作用:表示发送form-encoded的数据

2、@Multipart
作用:表示发送form-encoded的数据(适用于 有文件 上传的场景)

public interface MovieService {        /**         *表明是一个表单格式的请求(Content-Type:application/x-www-form-urlencoded)         * <code>Field("username")</code> 表示将后面的 <code>String name</code> 中name的取值作为 username 的值         */        @POST("/form")        @FormUrlEncoded        Call<ResponseBody> testFormUrlEncoded1(@Field("username") String name, @Field("age") int age);        /**         * {@link Part} 后面支持三种类型,{@link RequestBody}、{@link okhttp3.MultipartBody.Part} 、任意类型         * 除 {@link okhttp3.MultipartBody.Part} 以外,其它类型都必需带上表单字段({@link okhttp3.MultipartBody.Part} 中已经包含了表单字段的信息),         */        @POST("/form")        @Multipart        Call<ResponseBody> testFileUpload1(@Part("name") RequestBody name, @Part("age") RequestBody age, @Part MultipartBody.Part file);}
  • 网络请求参数
    1、@Header & @Headers
    作用:增加请求头 &增加不固定的请求头
// @Header@GET("user")Call<User> getUser(@Header("Authorization") String authorization)// @Headers@Headers("Authorization: authorization")@GET("user")Call<User> getUser()// 以上的效果是一致的。// 区别在于使用场景和使用方式// 1. 使用场景:@Header用于增加不固定的请求头,@Headers用于增加固定的请求头// 2. 使用方式:@Header作用于方法的参数;@Headers作用于方法

2、 @Body
作用:以 Post方式 传递 自己设置数据类型 给服务器,可以传输json文件
特别注意:假如提交的是一个Map,那么作用相当于 @Field

//POST 网络请求, RequestBody来实现传输JSON文件 @POST("rest/basis/modifyCrossMonthSubtractionContract") Call<ResponseBody> modifyCrossMonthSubtractionContract(@Body RequestBody body);//具体实现AddOrEditMonth addOrEditMonth = new AddOrEditMonth();addOrEditMonth.setLeftContract(mContractOne);addOrEditMonth.setLeftName(mNameOne);addOrEditMonth.setOldLetfContract(oldLetfContract);String d = GsonUtil.toJson(addOrEditMonth);RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"),GsonUtil.toJson(addOrEditMonth)); Call<ResponseBody> call2 = service.modifyCrossMonthSubtractionContract(body );

3、@Field & @FieldMap
作用:发送 Post请求 时提交请求的表单字段
具体使用:与 @FormUrlEncoded 注解配合使用

public interface MovieService {        /**         *表明是一个表单格式的请求(Content-Type:application/x-www-form-urlencoded)         * <code>Field("username")</code> 表示将后面的 <code>String name</code> 中name的取值作为 username 的值         */        @POST("/form")        @FormUrlEncoded        Call<ResponseBody> testFormUrlEncoded1(@Field("username") String name, @Field("age") int age);        /**         * Map的key作为表单的键         */        @POST("/form")        @FormUrlEncoded        Call<ResponseBody> testFormUrlEncoded2(@FieldMap Map<String, Object> map);}// 具体使用// @FieldCall<ResponseBody> call1 = service.testFormUrlEncoded1("Carson", 24);// @FieldMap // 实现的效果与上面相同,但要传入MapMap<String, Object> map = new HashMap<>();map.put("username", "Carson");map.put("age", 24);Call<ResponseBody> call2 = service.testFormUrlEncoded2(map);

4、@Url
作用:直接传入一个请求的 URL变量 用于URL设置

@GETCall<ResponseBody> testUrl@Url String ur);// 当有URL注解时,@GET传入的URL即可以省略// 当GET、POST...HTTP等方法中没有设置Url时,则必需使用 {@link Url}提供//用法String url = "/sso/checkregist/" + etLoginName.getText().toString();Call<ResponseBody> call2 = service.testUrl(map);

5、 @Path
作用:URL地址的缺省值

@GET("users/{user}/repos")Call<ResponseBody>  testPath(@Path("user") String user );// 访问的API是:https://api.github.com/users/{user}/repos// 在发起请求时, {user} 会被替换为方法的第一个参数 user(被@Path注解作用)

6、@Part & @PartMap
作用:发送 Post请求 时提交请求的表单字段与@Field的区别:功能相同,但携带的参数类型更加丰富,包括数据流,所以适用于 有文件上传 的场景
具体使用:与 @Multipart 注解配合使用

public interface MovieService {          //上传单个文件        @POST("/form")        @Multipart        Call<ResponseBody> testFileUpload1(@Part("name") RequestBody name, @Part("age") RequestBody age, @Part MultipartBody.Part file);        //上传单个文件        @POST("/form")        @Multipart        Call<ResponseBody> testFileUpload2(@PartMap Map<String, RequestBody> args, @Part MultipartBody.Part file);        //上传多个文件        @POST("/form")        @Multipart        Call<ResponseBody> testFileUpload3(@PartMap Map<String, RequestBody> args);}// 具体使用MediaType textType = MediaType.parse("text/plain");RequestBody name = RequestBody.create(textType, "Carson");RequestBody age = RequestBody.create(textType, "24");RequestBody file = RequestBody.create(MediaType.parse("application/octet-stream"), "这里是模拟文件的内容");// @PartMultipartBody.Part filePart = MultipartBody.Part.createFormData("file", "test.txt", file);Call<ResponseBody> call3 = service.testFileUpload1(name, age, filePart);ResponseBodyPrinter.printResponseBody(call3);// @PartMap// 实现和上面同样的效果Map<String, RequestBody> fileUpload2Args = new HashMap<>();fileUpload2Args.put("name", name);fileUpload2Args.put("age", age);//这里并不会被当成文件,由于没有文件名(包含在Content-Disposition请求头中),但上面的 filePart 有//fileUpload2Args.put("file", file);Call<ResponseBody> call4 = service.testFileUpload2(fileUpload2Args, filePart); //单独解决文件ResponseBodyPrinter.printResponseBody(call4);

7、@Query和@QueryMap
作用:用于 @GET 方法的查询参数(Query = Url 中 ‘?’ 后面的 key-value)
具体使用:配置时只要要在接口方法中添加一个参数就可:

  @GET("/")      Call<String> cate(@Query("cate") String cate);  @GET("News")  Call<NewsBean> getItem(@QueryMap Map<String, String> map);  // 其使用方式同 @Field与@FieldMap
四、创立一个Retrofit 实例,并且完成相关的配置:

配置了接口的 URL 和一个 converter , GsonConverterFactory 是默认提供的 Gson转换器。

public static final String URL = "https://liveapp.shmet.com/mapi/";//在创立Retrofit实例时通过.baseUrl()设置Retrofit retrofit = new Retrofit.Builder()                    .baseUrl(URL) //设置网络请求的Url地址                    .addConverterFactory(GsonConverterFactory.create())                    .build();
  • 网络请求的完整 Url =在创立Retrofit实例时通过.baseUrl()设置 +网络请求接口的注解设置(下面称 “path“ )
  • 具体整合的规则如下:

1、path = 完整的url

Url = "http://host:port/a/path"path = "http://host:port/a/path"baseUrl = 不设置(即:接口中的Url是一个完整的网址,在Retrofit的实例中可以不设置URL) 

2、path = 绝对路径

Url = "http://host:port/a/path"path = "/path"baseUrl = "http://host:port/a"

3、path = 相对路径 baseUrl = 目录形式

Url = "http://host:port/a/path"path = "path"baseUrl = "http://host:port/a/"

4、path = 相对路径 baseUrl = 文件形式

Url = "http://host:port/a/path"path = "path"baseUrl = "http://host:port/a"

建议采用第三种方式来配置,并尽量使用同一种路径形式。

五、取得api接口的代理商对象(即创立网络请求接口实例):
// 创立 网络请求接口 的实例MovieService request = retrofit.create(MovieService.class);//对 发送请求 进行封装Call<Reception> call = request.getCall();
六、发送网络请求(异步 / 同步),解决返回数据

通过response类的 body()对返回的数据进行解决

//发送网络请求(异步)call.enqueue(new Callback<Translation>() {            //请求成功时回调            @Override            public void onResponse(Call<Translation> call, Response<Translation> response) {                //请求解决,输出结果                response.body().show();            }            //请求失败时候的回调            @Override            public void onFailure(Call<Translation> call, Throwable throwable) {                System.out.println("连接失败");            }        });// 发送网络请求(同步)Response<Reception> response = call.execute();// 对返回数据进行解决response.body().show();
  • Retrofit 的详情先简单的详情这些,以后在更加详细的补充。

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » RxJava+Retrofit+OkHttp 网络框架封装(一)

发表回复