注意:以下分析都是基于Retrofit2
简单介绍
Retrofit发送网络请求通过okHttp,okhttp的诸多好处与内部实现机制,已经在之前的博客《OkHttp深入学习(一)——初探》进行了介绍。相对于直接使用okhttp的好处在于,它支持对Response接收数据进行解析,支持RxJava。
Retrofit和Volley一样,网络请求任务在背后线程中进行,返回结果的处理(或者说回调方法)在UI线程中执行。
此外这里给出Retrofit2相对于Retrofit1的改进
- 支持了在一个类型中的同步和异步,同时,一个请求也可以被真正地终止;Retrofit1之前是分开的,即需要定义两个方法
- 每一个 call 对象实例只能被调用一次,request 和 response 都是一一对应的;若需多次重复请求,则建议每次请求前clone一个call对象
- Response 对象增加了:响应码(the reponse code),响应消息(the response message),以及读取相应头(headers)
- @Url ,允许你直接传入一个请求的 URL,定义如下方法
- @GET
- Call<List<Contributor>> repoContributorsPaginate( @Url String url);
- 动态 URL Parameter
- String links = response.headers().get("Link");
- Call<List<Contributor>> nextCall = gitHubService.repoContributorsPaginate(nextLink);
基本使用
一、引入依赖
- compile 'com.google.code.gson:gson:2.6.2'
- compile 'com.squareup.retrofit2:retrofit:2.0.2'
- compile 'com.squareup.retrofit2:converter-gson:2.0.2'
- compile 'com.squareup.okhttp3:okhttp:3.2.0'
- 一般使用Retrofit还会使用它和RxJava配套使用,因此还需要添加如下依赖
- compile 'io.reactivex:rxjava:1.1.3'
- compile 'io.reactivex:rxandroid:1.1.0'
- compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'
- 为了使用更多的java注解添加下面的依赖
- provided 'org.glassfish:javax.annotation:10.0-b28'
二、定义网络业务接口
Retrofit的网络请求都是写在一个接口中,并使用一定的注释如下面一组请求接口:注意接口中的每个方法的参数都需要使用标注,不采用标注将会报错。
- public interface MyApiEndpointInterface {
- @GET("users/{username}")
- Call<User> getUser(@Path("username") String username,@Header("Cache-Control") int maxAge);
-
- @Headers({"Cache-Control: max-age=640000", "User-Agent: My-App-Name"})
- @POST("users/new")
- Call<User> createUser(@Body User user,@Query("sort") String sort);
-
- @FormUrlEncoded
- @POST("some/endpoint")
- Call<SomeResponse> someEndpoint(@FieldMap Map<String, String> names);
-
- @POST("https://blog.csdn.net/") //note3
- Call<Response<User>> getUser(@Query("name") String name);
-
- @Multipart
- @POST("some/endpoint")
- Call<Response> uploadImage(@Part("description") String description, @Part("image") RequestBody image)
-
- @GET("users/{username}")
- void getUser(@Path("username") String username, Callback<User> cb);
- }
1、Retrofit的网络请求返回的结果都是call<?>的形式,?代表希望对Response body解析得到的数据类型;如果想直接获得Responsebody中的内容,可以定义网络请求返回值为Call<ResponseBody>
2、Retrofit的注解有如下几种常见注解
@GET 发送get方法的请求,@POST发送post方法的请求,@Header 网络请求的Header部分的键值对
@Body Post请求报文的Body内容,内容往往是一个对Java Bean解析后得到的JSON String,@Path网络路径的缺省值,@Query网络请求地址后面的查询键值对,如www.baidu.com/s?wd=REST&rsv_spt=1.
@FormUrlEncoded 和 @FieldMap配套使用,用于向Post表单传入键值对
3、一旦创建一个Retrofit实例就意味着网络请求根目录已经确定,但是Retrofit支持动态改变网络请求根目录。
4、使用@Multipart 标注的网络请求,用于上传文件;同时该请求必须在请求方法的参数中有一个使用@Part注解的参数。下面给出一个简单的使用例子
- MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
- file = new File("/storage/emulated/0/Pictures/MyApp/test.png");
- RequestBody requestBody = RequestBody.create(MEDIA_TYPE_PNG, file);
- Call<Response> call = apiService.uploadImage("test", requestBody);
5、用于发送一个异步请求,不过在Retrofit2中已经没有这个了,异步请求和同步请求已经被合并。即通过Call<?>的execute和queue方法分别发送同步和异步请求
三、得到网络业务接口的实体
- public static final String BASE_URL = "http://api.myservice.com/";
- Retrofit retrofit = new Retrofit.Builder()
- .baseUrl(BASE_URL)
- .addConverterFactory(GsonConverterFactory.create())
- .build();
- MyApiEndpointInterface apiService = retrofit.create(MyApiEndpointInterface.class);
1、获得一个Retrofit对象
2、由retrofit得到一个网络请求接口的实现类
四、使用接口实体获取Response
- Call<User> call = apiService.getUser("evan",5000);
- 同步请求:
- Response<User> response = call.execute();
- 异步请求:
- call.enqueue(new Callback<User>() {
- @Override
- public void onResponse(Call<User> call, Response<User> response) {
- ....
- }
- });
call只能使用一次,调用第二次的时候,就会出现失败的错误。当你想要多次请求一个接口的时候,直接用 clone 的方法来生产一个新的,相同的可用对象,clone代价很低。
Retrofit2 中 Response 对象增加了曾经一直被我们忽略掉的重要元数据:响应码(the reponse code),响应消息(the response message),以及读取相应头(headers){cookies}。
五、关于授权
-
- Interceptor interceptor = new Interceptor() {
- @Override
- public okhttp3.Response intercept(Chain chain) throws IOException {
- Request newRequest = chain.request().newBuilder().addHeader("User-Agent", "Retrofit-Sample-App").build();
- return chain.proceed(newRequest);
- }
- };
-
- OkHttpClient.Builder builder = new OkHttpClient.Builder(); <li class="alt" style="border-style: none none none solid; border-left-width: 3px; border-left-color: rgb(108, 226, 108); list-style: decimal-leading-zero outside; color: inherit; line-height: 18px; margin: 0px !important; padding: 0px 3px 0px 10px !impor