Android开发经验谈Android开发程序员

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

2019-03-11  本文已影响28人  涛涛123759
首先简单介绍Retrofit、OKHttp和RxJava之间的关系:

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

Retrofit 创建过程和参数的讲解

一、引入Retrofit的包,在build.gradle文件中添加如下配置:
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);
}

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

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);

}
// @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();

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();
上一篇下一篇

猜你喜欢

热点阅读