目录
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
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);
}
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);
}
}
public interface Api{
@GET("...")
Call getDate3(
@Header("Content-Range") String contentRange,
@Query("q") String name;
}
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())
@GET("group/id/users")
Call> groupList(@Query("sort") String sort);
@GET("group/id/users")
Call> groupList(@QueryMap Map options);
使用:所有的参数集合在统一的map中即可
Map
map.put("q", "小王子");
map.put("tag", null);
一种方式是添加多个@Query参数,还有一种简便的方式是将所有的value放置在列表中,然后在同一个@Query下完成添加
实例代码如下:
public interface Api{
@GET("...")
Call<...> getSearchBooks(@Query("q") List
}
最终请求路径为:?q=XXX&q=XXX
如果请求参数为非必填,也就是说即使不传该参数,服务端也可以正常解析。只需填null到入参即可,如下:
public interface Api{
@GET("...")
Call getDate3(
@Query("q") String name;
}
q为非必传,则api.getDate3(null);
占位id,而非拼接路径
@GET("group/{id}/users")
Call> groupList(@Path("id") int groupId);
Post请求需要把请求参数放置在请求体中,而非拼接在url后面。如果没有添加转换器,只能使用RequestBody。
如果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;
}
@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将会被编码,即将中文和特殊字符进行编码转换
public interface Api {
@GET("...")
Call
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;
}
}
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方法可以取消请求,前提是该请求还没有执行
//接口类
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);
}
// 从文件选择器或者摄像头中获取文件的路径
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);
}