一、简介
Retrofit是一个RESTful的HTTP网络请求框架的封装,RESTful介绍见博客《RESTful API 最佳实践》。网络请求的工作本质上是OkHttp 完成,Retrofit仅负责网络请求接口的封装。App应用程序通过 Retrofit 请求网络,实际上是使用Retrofit接口层封装请求参数、Header、Url 等信息,之后由OkHttp 完成后续的请求操作。在服务端返回数据之后,OkHttp将原始的结果交给Retrofit,Retrofit根据用户的需求对结果进行解析。
二、使用步骤
1、在build.gradle中添加依赖
compile 'com.squareup.retrofit2:retrofit:2.0.2'
2、在AndroidManifest.xml中添加网络权限
<uses-permission android:name="android.permission.INTERNET" />
3、创建描述网络请求的接口
Retrofit将Http请求抽象成Java接口:采用注解描述网络请求参数和配置网络请求参数,用动态代理将该接口的注解“翻译”成一个Http请求,最后再执行Http请求。注意接口中的每个方法的参数都需要使用注解标注,否则会报错。
新建接口RequestInterface,使用注解标记请求方法和请求url。
public interface RequestInterface {
@GET("/OkHttpTest/OkHttpServlet")
Call<String> get();
}
4、创建Retrofit实例
// OkHttp报文打印拦截器
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(String message) {
Log.i(TAG, "----http报文:" + message);
}
});
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
// OkHttp配置
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.build();
// Retrofit配置
retrofit = new Retrofit.Builder()
.baseUrl("http://192.168.10.160:8080")
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build();
1)、baseUrl()方法
网络请求的完整Url =创建Retrofit实例时baseUrl()设置 +网络请求接口的注解设置
2)、client()方法
client()设置OkHttp,我们可以配置OkHttp的一些参数,然后通过该方法设置到Retrofit中
3)、addConverterFactory()方法
addConverterFactory设置数据解析器
5、创建网络请求接口实例
RequestInterface requestInterface = retrofit.create(RequestInterface.class);
通过rerequestInterface就可以请求网络了
6、发送网络请求
1)、发送同步请求
Call<String> call = RetrofitUtil.getInstance().getApi().get();
Response<String> response = call.execute();
注意call.execute()必须在子线程调用
2)、发送异步请求
Call<String> call = RetrofitUtil.getInstance().getApi().getAddHeader();
call.enqueue(new Callback<String>() {
@Override
public void onResponse(Call<String> call, Response<String> response) {
if (response.isSuccessful()) {
tvMsg.append(response.body().toString());
} else {
tvMsg.append("response code is " + response.code());
}
}
@Override
public void onFailure(Call<String> call, Throwable t) {
tvMsg.append(t.getMessage());
}
});
call.enqueue()可以直接在主线程中调用
三、Retrofit注解
Retrofit配置Http请求方法、请求地址、请求参数等都是使用注解的方式,因此Retrofit的注解使用非常重要。所有注解统计如下:
1、网络请求方法
标注Http请求的方法
1)、上面的注解只能修饰方法,因为定义注解时设置如下:@Target(METHOD),Target设置时METHOD
2)、使用@GET和@POST
URL通过这些注解后的()传入
public interface RequestInterface {
@GET("/OkHttpTest/OkHttpServlet")
Call<String> get();
@POST("/OkHttpTest/OkHttpServlet")
Call<String> postBody(@Body RequestBody requestBody);
}
3)、使用@HTTP
替换@GET、@POST、@PUT、@DELETE、@HEAD注解的作用及更多功能拓展,通过属性method、path、hasBody进行设置
public interface RequestInterface {
@HTTP(method = "GET", path = "/OkHttpTest/OkHttpServlet", hasBody = false)
Call<String> testHttp();
@HTTP(method = "POST", path = "/OkHttpTest/OkHttpServlet", hasBody = true)
Call<String> testHttp(@Body String body);
}
2、标记类注解
标记类注解都是配置方法的
1)、@FormUrlEncoded
表示发送form-encoded的数据,每个键值对需要用@Filed来注解键名,值通过方法的形参传入。
public interface RequestInterface {
@POST("/OkHttpTest/OkHttpServlet")
@FormUrlEncoded
Call<String> postForm(@Field("key1") String value1, @Field("key2") String value2);
}
2)、@Multipart
表示发送form-encoded的数据,适用于文件上传的场景,每个键值对需要用@Part来注解键名,随后的对象需要提供值。
public interface RequestInterface {
/**
* @Part后可以用任意类型的对象。是MultipartBody.Part时Part不用指定表单字段名,因为MultipartBody.Part 中已经指定了,其他类型需要指定表单字段名。
* 使用MultipartBody.Part
*/
@POST("/OkHttpTest/OkHttpServlet")
@Multipart
Call<String> postPart(@Part MultipartBody.Part part);
/**
* 使用RequestBody
*/
@POST("/OkHttpTest/OkHttpServlet")
@Multipart
Call<String> postPart(@Part("part1") RequestBody part1, @Part("part2") RequestBody part2);
/**
* 使用String
*/
@POST("/OkHttpTest/OkHttpServlet")
@Multipart
Call<String> postPart(@Part("part1") String part1, @Part("part2") String part2);
/**
* 使用自定义对象Student
* 如果转换器是.addConverterFactory(GsonConverterFactory.create())会自动将对象转换为json字符串
*/
@POST("/OkHttpTest/OkHttpServlet")
@Multipart
Call<String> postPart(@Part("part1") Student part1, @Part("part2") Student part2);
}
调用如下:
MultipartBody.Part part = MultipartBody.Part.createFormData("key", "value");
// MultipartBody.Part part = MultipartBody.Part.create(RequestBody.create(MediaType.parse("text"), "MultipartBody"));
Call<String> partCall = RetrofitUtil.getInstance().getApi().postPart(part);
try {
partCall.execute();
} catch (IOException e) {
e.printStackTrace();
}
RequestBody requestBodyPart = RequestBody.create(MediaType.parse("text"), "post body");
partCall = RetrofitUtil.getInstance().getApi().postPart(requestBodyPart, requestBodyPart);
try {
partCall.execute();
} catch (IOException e) {
e.printStackTrace();
}
partCall = RetrofitUtil.getInstance().getApi().postPart("part1", "part2");
try {
partCall.execute();
} catch (IOException e) {
e.printStackTrace();
}
partCall = RetrofitUtil.getInstance().getApi().postPart(new Student("小王", 18), new Student("小丽", 19));
try {
partCall.execute();
} catch (IOException e) {
e.printStackTrace();
}
3、网络请求参数注解
用于标注Http的请求参数,如头、body、form表单数据等
1)、 @Headers
添加请求头,头的信息是固定的,不能通过方法的形参设置。可以添加多个头。
添加一个头
// 添加一个head
@GET("/OkHttpTest/OkHttpServlet")
@Headers("head1:head1_value")
Call<String> getAddHeader();
添加多个头,头之间用逗号分隔,所有头外面加一个{}
@GET("/OkHttpTest/OkHttpServlet")
@Headers({"Authorization:authorization","head2:head2_value"})
Call<String> getAddHeader();
2)、Header
添加不固定的头,值通过方法的形参设置。
@GET("/OkHttpTest/OkHttpServlet")
Call<String> getAddConfigHeader(@Header("config_header") String header);
@Header注解中配置的是头的key
3)、Body
4)、@Field
向post请求的表单中传入键值对。@Field注解中指定键名
@POST("/OkHttpTest/OkHttpServlet")
@FormUrlEncoded
Call<String> postForm(@Field("key1") String value1, @Field("key2") String value2);
5)、@FieldMap
向post请求的表单中传入键值对。适合键值对比较多的情况,传入的形参是Map。Form表单中的键值对就是Map中的键值对。
@POST("/OkHttpTest/OkHttpServlet")
@FormUrlEncoded
Call<String> postFormMap(@FieldMap Map<String, String> map);
6)、@Part
适合文件上送的场景。
@POST("/OkHttpTest/OkHttpServlet")
@Multipart
Call<String> postPart(@Part("part1") RequestBody part1, @Part("part2") RequestBody part2);
详见上面 三——2——(2)
7)、@PartMap
适合上送Part比较多的场景。
@POST("/OkHttpTest/OkHttpServlet")
@Multipart
Call<String> postPartMap(@PartMap Map<String, RequestBody> map);
8)、@Query
@GET("/OkHttpTest/OkHttpServlet")
Call<String> getWithQueryParam(@Query("query") String query);
@POST("/OkHttpTest/OkHttpServlet")
Call<String> getWithQueryParam(@Query("query") String query);
使用get和post都可以,都是生成key=values&key=value的形式,添加到url后面。生成的数据和@Field是一样的,区别是@Query数据添加到url后面,@Post数据添加到body中。
9)、@QueryMap
适合键值对比较多的情况。
@GET("/OkHttpTest/OkHttpServlet")
Call<String> getWithQueryParams(@QueryMap Map<String, String> map);
10)、@Path
用于实现动态设置url中某个path
@GET("/OkHttpTest/OkHttpServlet/{user}")
Call<String> getConfigPath(@Path("user") String user);
{user}指定可以被设置的path,形参会替换{user}
11)、@URL
用于实现动态配置url,在@GET注解中不设置url,在形参中设置,这样就可以动态改变url
@GET
Call<String> getConfigUrl(@Url String url, @Query("query1") String query);