android Retrofit
RESTful POJO <-> JSON
github retrofit怪盗kidou:你真的会用Retrofit2吗?Retrofit2完全教程
鸿洋_:Retrofit2 完全解析 探索与okhttp之间的关系
配置
dependencies {
compile 'com.google.code.gson:gson:2.3'
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'
compile 'com.squareup.okhttp:okhttp:2.4.0'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'
}
//解析库配置
Gson com.squareup.retrofit:converter-gson:2.0.0-beta2
Jackson com.squareup.retrofit:converter-jackson:2.0.0-beta1
Moshi com.squareup.retrofit:converter-moshi:2.0.0-beta1
Protobuf com.squareup.retrofit:converter-protobuf:2.0.0-beta1
Wire com.squareup.retrofit:converter-wire:2.0.0-beta1
Simple XML com.squareup.retrofit:converter-simplexml:2.0.0-beta1
//PROGUARD
# Platform calls Class.forName on types which do not exist on Android to determine platform.
-dontnote retrofit2.Platform
# Platform used when running on RoboVM on iOS. Will not be used at runtime.
-dontnote retrofit2.Platform$IOS$MainThreadExecutor
# Platform used when running on Java 8 VMs. Will not be used at runtime.
-dontwarn retrofit2.Platform$Java8
# Retain generic type information for use by reflection by converters and adapters.
-keepattributes Signature
# Retain declared checked exceptions for use by a Proxy instance.
-keepattributes Exceptions
使用
//1,定义业务请求接口
public interface GitHubService {
@GET("users/{user}")
Call<ResponseBody> repo(@Path("user") String user);
}
//2,需要创建Retrofit实例,并完成相应的配置
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/") //baseUlr必须以/(斜线)结束
.addConverterFactory(GsonConverterFactory.create())
//.addCallAdapterFactory(RxJavaCallAdapterFactory.create()) //RxJava
.build();
GitHubService service = retrofit.create(GitHubService.class);
//3,调用请求方法,并得到Call实例
Call<ResponseBody> call = service.repo("octocat");
//同步
ResponseBody repo = call.execute();
//异步
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
try {
System.out.println(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
t.printStackTrace();
}
});
//取消请求
call.cancel();
+RxJava
//1,接口设计:
public interface BlogService {
@POST("/blog")
Observable<Result<List<Blog>>> getBlogs();
}
//
//2,通过RxJavaCallAdapterFactory为Retrofit添加RxJava支持:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://localhost:4567/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
//
//3,使用:
BlogService service = retrofit.create(BlogService.class);
service.getBlogs()
.subscribeOn(Schedulers.io())
.subscribe(new Subscriber<Result<List<Blog>>>() {
@Override
public void onCompleted() {
System.out.println("onCompleted");
}
@Override
public void onError(Throwable e) {
System.err.println("onError");
}
@Override
public void onNext(Result<List<Blog>> blogsResult) {
System.out.println(blogsResult);
}
});
方法级注解
- 各种请求方法 : @GET @POST @PUT @DELETE @PATCH @HEAD @OPTIONS ("myPath")
baseUrl + myPath -->URL
- @HTTP
模拟各种请求方法 : @HTTP(method = "DELETE", path = "remove/", hasBody = true)
@HTTP String method():请求方式 String path():默认为"",值为请求的相对URL路径 boolean hasBody():默认为false @HTTP(method = "DELETE", path = "remove/", hasBody = true) Call<ResponseBody> deleteObject(@Body RequestBody object); - @Headers
请求头
@Headers String[] value(); @Headers({ "X-Foo: Bar", "X-Ping: Pong" }) @GET("deleteObject") Call(ResponseBody) deleteObject(@Query("id") String id);
标记注解
- @FormUrlEncoded +@Field或者@FieldMap
表明是一个表单格式的请求(Content-Type:application/x-www-form-urlencoded)
使用@Field或者@FieldMap注解和参数来指定每个表单项的key,value为参数的值。@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); - @Multipart +@Part或者@PartMap
发送multipart数据,
使用@Part或者@PartMap注解定义即将发送的每一个文件@Part支持类型: RequestBody(带上表单字段) okhttp3.MultipartBody.Part 任意类型(带上表单字段) @POST("form") @Multipart Call<ResponseBody> upload1(@Part("name") RequestBody name, @Part MultipartBody.Part file); @PartMap支持类型: RequestBody 其它的类型,被retrofit2.Converter转换 @POST("form") @Multipart Call<ResponseBody> upload2(@PartMap Map<String, RequestBody> args); - @Streaming
将返回值okhttp3.Response.body() body()转换为byte[]
参数级注解
- @Path
以接口参数代替URL中的变量 @Path("name") String myName --> {name}
String value():参数名称 boolean encoded() :指定的名称和值是否URL编码,默认为false(URL编码)。设置为true时,不进行URL编码 @GET("image/{id}") Call<ResponseBody> getInfo(@Path("id") int id); // 指定的名称和值默认URL编码 @GET("user/{name}") Call<ResponseBody> encoded(@Path("name") String name); // 指定的名称和值取消URL编码 @GET("user/{name}") Call<ResponseBody> notEncoded(@Path(value="http://blog.csdn.net/IO_Field/article/details/name", encoded=true) String name); - @Query @QueryMap
组合Url的查询字段 ?
@Query String value:默认为"",参数名称 bolean encoded:指定的名称和值是否已URL编码,默认为false, @GET("list") Call<ResponseBody> list(@Query("page") int page); // https://api.example.com/tasks?id=123 @GET("list") Call<ResponseBody> list(@Query("category") String ... page); @GET("search") Call<ResponseBody> list(@Query(value="http://blog.csdn.net/IO_Field/article/details/foo", encoded=true) String foo); @GET("tasks") Call<List<Task>> getTask(@Query("id") List<Long> taskIds); // https://api.example.com/tasks?id=123&id=124&id=125 @QueryMap bolean encoded:指定的名称和值是否已URL编码,默认为false, @GET("search") Call<ResponseBody> list(@QueryMap Map<String, String> filters); @GET("search") Call<ResponseBody> list(@QueryMap(encoded=true) Map<String, String> filters); - @Url
注解的值为请求的相对URL路径 不用设置请求方法的path值
@GET Call<ResponseBody> list(@Url String url); - @Field @FieldMap
@Field String value:默认为"",参数名称 bolean encoded:指定的名称和值是否已URL编码,默认为false, @FormUrlEncoded @POST("login") Call<ResponseBody> login(@Field("name") String name, @Field("pwd") String pwd); // {@code name=Bob+Smith&pwd=123} @FormUrlEncoded @POST("queryScore") Call<ResponseBody> queryScore(@Field("name") String... name); // {@code name=Bob&name=Jane} @FieldMap bolean encoded:指定的名称和值是否已URL编码,默认为false, @FormUrlEncoded @POST("things") Call<ResponseBody> things(@FieldMap Map<String, String> fields); - @Part @PartMap
@Part String value():默认为"",参数名称 String encoding():默认编码格式为 "binary"; @Multipart @POST("upload") Call<ResponseBody> upload( @Part("description") String description, @Part(value = "http://blog.csdn.net/IO_Field/article/details/image", encoding = "8-bit") RequestBody image); @PartMap String encoding():默认编码格式为 "binary"; @Multipart @POST("upload") Call<ResponseBody> upload(@Part("file") RequestBody file,@PartMap Map<String, RequestBody> params); - @Header @HeaderMap
通过接口参数设置header : @Header("Accept-Language") String lang
@Header String value:默认为"",header的key @GET("query") Call<ResponseBody> query(@Header("Accept-Language") String lang); @HeaderMap @GET("query") Call<ResponseBody> query(@HeaderMap Map<String, String> headers); - @Body
设置一个对象作为请求体,使用addConverterFactory()转换器 : @Body User user
@POST("users/new") Call<ResponseBody> getInfo(@Body User user);
Retrofit.Builder
- callbackExecutor(Executor)
指定Call.enqueue时使用的Executor,所以该设置只对返回值为Call的方法有效
- callFactory(Factory)
设置一个自定义的okhttp3.Call.Factory,那什么是Factory呢?OkHttpClient就实现了okhttp3.Call.Factory接口,下面的client(OkHttpClient)最终也是调用了该方法,也就是说两者不能共用
- client(OkHttpClient)
设置自定义的OkHttpClient,以前的Retrofit版本中不同的Retrofit对象共用同OkHttpClient,在2.0各对象各自持有不同的OkHttpClient实例,所以当你需要共用OkHttpClient或需要自定义时则可以使用该方法,如:处理Cookie、使用stetho 调式等
- validateEagerly(boolean)
是否在调用create(Class)时检测接口定义是否正确,而不是在调用方法才检测,适合在开发、测试时使用
Converter
- 在默认情况下Retrofit只支持将HTTP的响应体转换换为ResponseBody
- Converter用于将ResponseBody转换为其他的类型,将对象转换为request Body
- 配置Converter
Gson gson = new GsonBuilder() //配置你的Gson .setDateFormat("yyyy-MM-dd hh:mm:ss") .create(); Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://localhost:4567/") //可以接收自定义的Gson,当然也可以不传 .addConverterFactory(GsonConverterFactory.create(gson)) .build(); - 使用:Call<Result<Blog>> createBlog(@Body Blog blog);
- 自定义Converter
- 自定义CallAdapter
Retrofit的Url组合规则
- 注解中提供的url是完整的url,则url将作为请求的url。
- 注解中提供的url是不完整的url,且不以 / 开头,则请求的url为baseUrl+注解中提供的值
- 注解中提供的url是不完整的url,且以 / 开头,则请求的url为baseUrl的主机部分+注解中提供的值