Retrofit使用及解析(一)

目录

         1.设置请求头

1)方法头部定义

2)拦截器配置

3)动态配置

2.get请求参数@Query/@QueryMap/@Path

1)不变参数配置

2)@Query注解

3)@QueryMap

4) key字段同,value有多个

5) @query参数非必填

6) 占位请求参数@Path

3.post请求参数@Body

1)@Body

2)@FormUrlEncoded/@FieldMap发送date

4.简易封装

1)接口定义

2) 管理类

3) 调用

5.文件上传@Multipart

1) 多个文件上传demo


1.设置请求头

1)方法头部定义

public interface Api {

@Headers("Cache-Control: max-age=640000")
@GET("...")
  Call getDate1(@Query("q") String name);

@Headers({
      "Accept: application/vnd.yourapi.v1.full+json",
      "User-Agent: Your-App-Name"})
  @GET("...")
  Call<...> getDate2(@Query("q") String name);
}

2)拦截器配置

public class RequestInterceptor implements Interceptor {
  @Override
  public Response intercept(Chain chain) throws IOException {
      Request original = chain.request();
      Request request = original.newBuilder()
          .header("User-Agent", "Your-App-Name")
          .header("Accept", "application/vnd.yourapi.v1.full+json")
          .method(original.method(), original.body())
          .build();
      return chain.proceed(request);
  }
}

3)动态配置

public interface Api{
  @GET("...")
  Call getDate3(
  @Header("Content-Range") String contentRange, 
  @Query("q") String name;
}

2.get请求参数@Query/@QueryMap/@Path

1)不变参数配置

public class CustomInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        HttpUrl httpUrl = request.url().newBuilder()
                .addQueryParameter("token", "tokenValue")
                .build();
        request = request.newBuilder().url(httpUrl).build();
        return chain.proceed(request);
    }
}

使用:还需要在Retrofit创建client处完成添加:addInterceptor(new CustomInterceptor())

2)@Query注解

@GET("group/id/users")
Call> groupList(@Query("sort") String sort);

3)@QueryMap

@GET("group/id/users")
Call> groupList(@QueryMap Map options);

使用:所有的参数集合在统一的map中即可

Map options = new HashMap<>();

map.put("q", "小王子");

map.put("tag", null);

4) key字段同,value有多个

一种方式是添加多个@Query参数,还有一种简便的方式是将所有的value放置在列表中,然后在同一个@Query下完成添加

实例代码如下:

public interface Api{

@GET("...")

Call<...> getSearchBooks(@Query("q") List name);

}

最终请求路径为:?q=XXX&q=XXX

5) @query参数非必填

如果请求参数为非必填,也就是说即使不传该参数,服务端也可以正常解析。只需填null到入参即可,如下:

public interface Api{
  @GET("...")
  Call getDate3(
  @Query("q") String name;
}

q为非必传,则api.getDate3(null);

6) 占位请求参数@Path

占位id,而非拼接路径
@GET("group/{id}/users")
Call> groupList(@Path("id") int groupId);

3.post请求参数@Body

Post请求需要把请求参数放置在请求体中,而非拼接在url后面。如果没有添加转换器,只能使用RequestBody。

1)@Body

如果Post请求参数有多个,那么统一封装到类中应该会更好,这样维护起来会非常方便

@FormUrlEncoded
@POST("book/reviews")
Call addReviews(@Body Reviews reviews);

public class Reviews {
    public String book;
    public String title;
    public String content;
    public String rating;
}

2)@FormUrlEncoded/@FieldMap发送date

@FormUrlEncoded
@POST("user/edit")
Call updateUser(
@Field("first_name") String first,
@Field("last_name") String last);

或者@FieldMap提交整个map:

@FormUrlEncoded
@POST("user/login.do")
Call login(@FieldMap Map formMap);

补充:

a:@FormUrlEncoded自动将请求参数的类型调整为application/x-www-formurlencoded。假如content传参为Good Luck,那么最后得到的请求体就是content=Good+Luck。且FormUrlEncoded不能用于Get请求。

b:@Field注解将每一个请求参数都存放至请求体中,还可以添加encoded参数,该参数为boolean型,具体的用法为

@Field(value = "book", encoded = true) 。encoded参数为true,key-value-pair将会被编码,即将中文和特殊字符进行编码转换

4.简易封装

1)接口定义

public interface Api {
    @GET("...")
    Call getSearch(@QueryMap Map options);
} 
  

2) 管理类

public class BaseRetrofit {

    //api接口
    Api api;
    //对应的reteofit
    private Retrofit retrofitSearchBooks;
    private static Context mcontext;
    private OkHttpClient okHttpClient;
    private static BaseRetrofit base_retrofit;

    public static BaseRetrofit get_face_retrofit(Context context) {
        mcontext = context;
        if (base_retrofit == null) {
            base_retrofit = new BaseRetrofit();
        }
        return base_retrofit;
    }

    private BaseRetrofit() {
        /**拦截器*/
        HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
        httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

        /**共用一个okhttp*/
        okHttpClient = new OkHttpClient.Builder()
                .addInterceptor(httpLoggingInterceptor)
                .build();

        /**单个请求*/
        retrofitSearchBooks = new Retrofit.Builder()
                .client(okHttpClient)
                .baseUrl("https://api-cn.faceplusplus.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();
    }

    /**
     * 对外暴露接口类的对象
     */
    public Api getSearchBooksApi() {
        if (api == null) {
            api = retrofitSearchBooks.create(Api.class);
        }
        return api;
    }
}

3) 调用

 public void text()  {
        Api api = BaseRetrofit.get_face_retrofit(context).getSearchBooksApi();
        Call call=api.getSearch(map);
        try {
            //同步
//            Response response= call.execute();
            //异步
            call.enqueue(new Callback() {
                @Override
                public void onResponse(Call call, Response response) {

                }

                @Override
                public void onFailure(Call call, Throwable t) {

                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Call提供了cancel方法可以取消请求,前提是该请求还没有执行

5.文件上传@Multipart

//接口类
public interface FileUploadService {  
    // 上传单个文件
    @Multipart
    @POST("upload")
    Call uploadFile(
            @Part("description") RequestBody description,
            @Part MultipartBody.Part file);

    // 上传多个文件
    @Multipart
    @POST("upload")
    Call uploadMultipleFiles(
            @Part("description") RequestBody description,
            @Part MultipartBody.Part file1,
            @Part MultipartBody.Part file2);
}

1) 多个文件上传demo

// 从文件选择器或者摄像头中获取文件的路径
Uri file1Uri = ... 
Uri file2Uri = ... 

// 创建上传的service实例
FileUploadService service = ServiceGenerator.createService(FileUploadService.class);

// 创建文件的part (photo, video, ...)
MultipartBody.Part body1 = prepareFilePart("video", file1Uri);  
MultipartBody.Part body2 = prepareFilePart("thumbnail", file2Uri);

// 添加其他的part
RequestBody description = createPartFromString("hello, this is description speaking");

// 最后执行异步请求操作
Call call = service.uploadMultipleFiles(description, body1, body2);  
call.enqueue(new Callback() {  
    @Override
    public void onResponse(Call call,
            Response response) {
        Log.v("Upload", "success");
    }
    @Override
    public void onFailure(Call call, Throwable t) {
        Log.e("Upload error:", t.getMessage());
    }
});

2个工具类方法:

public static final String MULTIPART_FORM_DATA = "multipart/form-data";

//将string转化成MediaType
@NonNull
private RequestBody createPartFromString(String descriptionString) {  
    return RequestBody.create(
 MediaType.parse(MULTIPART_FORM_DATA), descriptionString);
}

@NonNull
private MultipartBody.Part prepareFilePart(String partName, Uri fileUri) {  
    File file = FileUtils.getFile(this, fileUri);
    // 为file建立RequestBody实例
    RequestBody requestFile =
        RequestBody.create(MediaType.parse(MULTIPART_FORM_DATA), file);
    // MultipartBody.Part借助文件名完成最终的上传
    return MultipartBody.Part.createFormData(partName, file.getName(), requestFile);
}

 

你可能感兴趣的:(android框架源码分析)