美文网首页Android开发经验谈Android开发程序员
RxJava+Retrofit+OkHttp 网络框架封装(一)

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

作者: 涛涛123759 | 来源:发表于2019-03-11 17:14 被阅读28次
    首先简单介绍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'//导入retrofit
    compile 'com.google.code.gson:gson:2.6.2'//Gson 库
    //下面两个是RxJava 和 RxAndroid
    compile 'io.reactivex.rxjava2:rxandroid:2.0.2'
    compile 'io.reactivex.rxjava2:rxjava:2.x.y'
    compile 'com.squareup.retrofit2:converter-gson:2.3.0'//转换器,请求结果转换成Model
    compile '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);
    
    }
    
    // 具体使用
    // @Field
    Call<ResponseBody> call1 = service.testFormUrlEncoded1("Carson", 24);
    
    // @FieldMap 
    // 实现的效果与上面相同,但要传入Map
    Map<String, Object> map = new HashMap<>();
    map.put("username", "Carson");
    map.put("age", 24);
    Call<ResponseBody> call2 = service.testFormUrlEncoded2(map);
    

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

    @GET
    Call<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"), "这里是模拟文件的内容");
    
    // @Part
    MultipartBody.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 的介绍先简单的介绍这些,以后在更加详细的补充。

    相关文章

      网友评论

        本文标题:RxJava+Retrofit+OkHttp 网络框架封装(一)

        本文链接:https://www.haomeiwen.com/subject/jpeqpqtx.html