Retorfit菜鸟使用入门

开始使用

retrofit本身是对网络请求的再封装,所以需要其它网络请求库的支持比如Okhttp
converter-gson是json的转换器

在app的build.gradle下添加依赖:

1
2
3
compile 'com.squareup.okhttp3:okhttp:3.8.1'
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'

初始化Retrofit

新建Retrofit网络请求客户端,并进行配置
深度的配置可以传入OkhttpClient后面会提到部分

1
2
3
4
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("url")//服务器地址
.addConverterFactory(GsonConverterFactory.create())//json转换器,可以自定义
.build();

创建Get请求

Retrofit的请求都是通过创建接口,并通过方法上的注解获取需要的参数

@GET表示get请求方式,()内可以传入接口地址

@Query后接get请求的参数,将会拼接到地址后

@QueryMap后接一个map,map存放参数,适合参数较多的情况

Call是网络请求的操作对象,泛型指定了返回的数据类型

  1. 创建请求接口

    1
    2
    3
    4
    5
    6
    7
    public interface DemoApi {
    @GET("url")
    Call<ResponseBody> get1(@Query("var1") String var1,@Query("var2") String var2);
    @GET("url")
    Call<ResponseBody> get2(@QueryMap Map<String, String> vars);
    }
  2. 生成接口,获得Call对象

    如果不想传递某个参数,参数值为null即可

    1
    2
    3
    4
    5
    6
    7
    8
    DemoApi demoApi = retrofit.create(DemoApi.class);
    //@Query
    Call<ResponseBody> call = demoApi.get1("var1","var2");
    //@QueryMap
    Map<String, String> vars = new HashMap<>();
    vars.put("var1","var1");
    vars.put("var2","var2");
    Call<ResponseBody> call = demoApi.get2(vars);

创建post请求

@POST代表这个方法是post请求

@FormUrlEncoded表示将表单内的数据处理为键值对

@Field后接需要传递的参数

@FieldMap适用于参数较多的情况,可以放参数放到一个map中

  1. 创建请求接口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public interface DemoApi {
    @FormUrlEncoded
    @POST("url")
    Call<ResponseBody> post1(@Field("var1") String var1,@Field("var2") String var2);
    }
    @FormUrlEncoded
    @POST("url")
    Call<ResponseBody> post2(@FieldMap Map<String, String> vars);
  2. 生成接口,获得Call对象

    1
    2
    3
    4
    5
    6
    7
    8
    DemoApi demoApi = retrofit.create(DemoApi.class);
    //@Field
    Call<ResponseBody> call = demoApi.post1("var1","var2");
    //@FieldMap
    Map<String, String> vars = new HashMap<>();
    vars.put("var1","var1");
    vars.put("var2","var2");
    Call<ResponseBody> call = demoApi.post2(vars);

如何请求

发起请求

  1. 同步请求

    1
    Response<ResponseBody> response = call.execute();
  2. 异步请求

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    call.enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
    //请求成功
    //响应码 response.code()在[200..300)区间内
    if (response.isSuccessful()) {
    //数据只能读取一次
    Log.e(TAG, "onResponse: " + response.body().string());
    //第二次打印为空
    Log.e(TAG, "onResponse: " + response.body().string());
    //记得关闭回收资源
    response.body().close();
    }
    }
    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
    }
    });
  3. 每个请求对象只能请求一次,但是我们可以利用方法复制一份再请求

    1
    2
    Call<ResponseBody> clone = call.clone();
    clone.execute();

取消请求

1
2
3
4
5
6
//请求是否已经取消
call.isCanceled();
//请求是否已近完成
call.isExecuted();
//取消请求
call.cancel();

:warning:注意:

1
2
3
4
5
6
7
8
9
10
new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
//取消请求,会调用该方法
}
});

其它注解

辅助作用,适用于post,get,可以混合使用

@Body

可以把参数封装成为一个对象,请求的时候传一个对象就可以了

注意不能可@FormUrlEncoded同时使用

1
2
3
4
5
6
7
@POST("url")
Call<String> post(@Body Bean bean);
public class Reviews {
public String var1;
public String var2;
}

@Path

根据传递的参数动态改变相对地址,例如分页,分类等

1
2
@GET("list/{page}")
Call<BookResponse> getBook(@Path("page") String page);

@Url

当我们的地址和basUrl没有关系的时候,可以传递一个完整的地址

1
2
@GET
public Call<ResponseBody> get(@Url String url);

@Headers

给请求添加请求头

1
2
3
4
@Headers({ "Accept: application/vnd.yourapi.v1.full+json",
"User-Agent: Your-App-Name" })
@GET("url")
Call<BookSearchResponse> getSearchBooks(@Query("var") String var);

上传文件

  1. 单张图片上传

    @Multipart表示表单上传数据

    @Part后接参数

    • 请求接口
    1
    2
    3
    @Multipart
    @POST(url)
    Call<ResponseBody> upload(@Part MultipartBody.Part img);
    • 创建参数和请求
    1
    2
    3
    4
    5
    6
    7
    File file = new File(Environment.getExternalStorageDirectory(), "xxx.jpg");
    //构造请求体
    RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file);
    MultipartBody.Part part = MultipartBody.Part.createFormData("img", file.getName(), requestBody);
    UploadApi uploadApi = retrofit.create(UploadApi.class);
    Call call = uploadApi.upload( part);
  2. 多图以及文字上传

    • 请求接口
    1
    2
    3
    @Multipart
    @POST(url)
    Call<ResponseBody> upload(@Part() List<MultipartBody.Part> imgs,@Part String var);
    • 创建参数和请求
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    List<MultipartBody.Part> parts = new ArrayList<>();
    File file1 = new File(Environment.getExternalStorageDirectory(), "1.jpg");
    File file2 = new File(Environment.getExternalStorageDirectory(), "2.jpg");
    //构造请求体
    RequestBody requestBody1 = RequestBody.create(MediaType.parse("multipart/form-data"), file1);
    MultipartBody.Part part1 = MultipartBody.Part.createFormData("img1", file1.getName(), requestBody1);
    RequestBody requestBody2 = RequestBody.create(MediaType.parse("multipart/form-data"), file2);
    MultipartBody.Part part2 = MultipartBody.Part.createFormData("img2", file2.getName(), requestBody2);
    parts.add(part1);
    parts.add(part2);
    UploadApi uploadApi = retrofit.create(UploadApi.class);
    Call call = uploadApi.upload(parts,"var");

强大的拦截器

拦截器其实是okhttp的扩展用法,所以拦截器都是给okhttpClien添加,然后把okhttpClient设置到retrofit

日志拦截器

官方提供了一个打印日志的库

  1. 添加依赖

    1
    compile 'com.squareup.okhttp3:logging-interceptor:3.8.1'
  2. 创建

    1
    2
    3
    4
    5
    6
    HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
    logging.setLevel(HttpLoggingInterceptor.Level.BODY);
    OkHttpClient client = new OkHttpClient.Builder()
    .addInterceptor(logging)
    .addInterceptor(new CustomerInterceptor())
    .build();
  3. 设置

    1
    2
    3
    4
    5
    retrofit = new Retrofit.Builder()
    .baseUrl("url")
    .addConverterFactory(GsonConverterFactory.create())
    .client(client)
    .build();

自定义拦截器,添加统一参数

自定义接口都是继承Retrofit的拦截器类然后自己改写

下面这个就是继承拦截器然后获取请求,在请求的基础上复制一个请求,给请求添加统一的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class CustomerInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
HttpUrl httpUrl = request.url().newBuilder()
.addQueryParameter("token", "xxxx-xxx-xxx-xxx")
.addQueryParameter("deviceType","android")
.build();
request = request.newBuilder().url(httpUrl).build();
return chain.proceed(request);
}
}
client.addInterceptor(new CustomerInterceptor())

结语

这一次只是初步的记录了retrofit的简单使用,欢迎大家吐槽.

下一步应该了解如何与Rxjava的结合使用(没办法,现在你说你不会这两个都会感觉不好意思).

参考文章

http://duanyytop.github.io/2016/08/06/Retrofit%E7%94%A8%E6%B3%95%E8%AF%A6%E8%A7%A3/?utm_source=tuicool&utm_medium=referral