Retrofit的Get与Post请求

1.Retrofit简介

Retrofit无疑是当下最流行的Android网络请求框架了,是Square提供的开源产品。官方网站是这样介绍Retrofit的—-A type-safe HTTP client for Android and Java,为Android平台的应用提供一个类型安全的HTTP客户端。Retrofit 是一套注解形式的网络请求封装库,它的强大在于让代码结构更加清晰,它可以直接解析JSON数据变成JAVA对象,支持回调操作,处理不同的结果。

2.准备工作

添加依赖:

在AndroidStudio的项目中,在build.gradle文件中添加以下引用:

 compile 'com.squareup.retrofit2:retrofit:2.1.0'

compile 'com.squareup.retrofit2:converter-scalars:2.0.0-beta4'//ConverterFactory的String依赖包
//ScalarsConverterFactory.create()

数据准备:

使用okhttp请求网络数据的时候,我们需要把服务器返回的JSON数据手动转换成我们的Java对象。而在上文我们提到,Retrofit可以直接解析JSON数据变成JAVA对象,这也是Retrofit灵活与强大的体现。看看怎么实现的

 compile 'com.squareup.retrofit2:converter-gson:2.1.0'

首先添加以上引用,这里除了gson以外,还有其他的选择。Retrofit自动转化的核心就是根据服务器返回的json数据定制一个javabean,举个例子:

Retrofit的Get与Post请求_第1张图片

服务器返回的很常见的一种数据类型,jsonobject对象里面包括一个jsonarray数组,数组里面包括很多jsonobject对象。我们需要拿到的就是这些jsonobject里的id与name的。看看定制的javabean该怎么写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class CityManager {
 
     private List cities;
 
     public List getCities() {
         return cities;
     }
 
     public void setCities(List cities) {
         this .cities = cities;
     }
 
     public class CityBean {
         private String id;
         private String name;
 
         public String getId() {
             return id;
         }
 
         public void setId(String id) {
             this .id = id;
         }
 
         public String getName() {
             return name;
         }
 
         public void setName(String name) {
             this .name = name;
         }
 
     }
}

这里有一点需要特别注意的是:保证我们定制的javabean对象的字段要和服务器返回的数据字段一一对应,不然解析会出错

3.基本使用

1.get请求

请求城市数据的url为:http://111.111.1.11/Base/getCities?clientVersion=205002&version=1622

请求方式为get,请求参数为clientVersion与version,请求数据为城市的id与name,那么使用Retrofit完成数据请求的流程如下:

1
2
3
4
5
6
7
8
9
10
11
public class ApiService {
 
     public static final String RES_GET_CITIES_LIST =  "Base/getCities" ;
 
     public interface CityService {
         @GET (RES_GET_CITIES_LIST)
         Call getCity
         ( @QueryMap Map queryMap);
     }
 
  }

retrofit在使用过程中,需要定义一个接口对象,@GET标识为get请求,@GET中所填写的value值和baseUrl组成完整的路径,baseUrl在构造retrofit对象时给出。@QueryMap 标识为接口查询的关键字,这里需要的参数有两个,所以我使用了@QueryMap,与下面这种写法是等价的:

1
2
Call getCity
( @Query ( "clientVersion" ) String clientVersion,  @Query ( "version" ) String version);

接口中的方法必须要有返回值,这里将我们定制的javabean对象传进去即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public static final String BASE_URL =  "http://111.111.1.11/" ;
Map queryMap =  new HashMap<>();
queryMap.put( "clientVersion" "205002" );
queryMap.put( "version" "1622" );
Retrofit  retrofit =  new Retrofit.Builder()
             .baseUrl(BASE_URL)
             .addConverterFactory(GsonConverterFactory.create())
             .build();
ApiService.CityService cityService = retrofit.create(ApiService.CityService. class );
Call call = cityService.getCity(queryMap);
     call.enqueue( new Callback()
     {
         @Override
         public void onResponse(Call call, Response response)
         {
            ArrayList cityNames =  new ArrayList<>();
            ArrayList cityIds =  new ArrayList<>();
            for (CityManager.CityBean city : response.body().getCities()) {
                 cityNames.add(city.getName());
                 cityIds.add((city.getId()));
            }
 
         }
 
         @Override
         public void onFailure(Call call, Throwable t)
         {
           //进行异常情况处理
         }
     });

Retrofit的构建使用的是构造者模式,指定一个baseUrl,添加一个对象转换器,用于将服务器返回的数据转换成对应实体类对象。构造完成以后,调用create方法就可以拿到我们的接口实例。然后再调用我们之前定义好的获取城市的方法,得到一个call对象,通过call.enqueue即可完成异步的网络请求。最后在数据请求成功的时候,通过response.body()即可拿到我们定义在Call< T >中需要返回的对象,数据请求失败的时候,进行异常的处理。

2.post请求

同样是上面的url,如果改为post请求,要求提交的参数有两个,userId:1001,userName:kaikai,那我们应该怎样实现呢:

1
2
3
4
5
6
7
8
9
10
11
public class ApiService {
 
     public static final String RES_GET_CITIES_LIST =  "Base/getCities" ;
     public interface CityService {
         @POST (RES_GET_CITIES_LIST)
         @FormUrlEncoded
         Call getCity
         ( @QueryMap Map queryMap, @FieldMap Map queryBody);
     }
 
  }

@POST标识为post请求,@FormUrlEncoded 与 @FieldMap注解结合表示以表单的方式传递键值对,与下面这两种写法是等价的:

1
2
Call getCity
( @QueryMap Map queryMap,  @Field ( "userId" ) String userId,  @Field ( "userName" ) String userName);

这种写法很好理解,将FieldMap拆分成了两个Field

1
Call getCity( @QueryMap Map queryMap,  @Body User user);

@Body注解标识的是我们的post参数对象,在使用的时候是:

1
cityService.getCity(queryMap, new User( "1001" , "kaikai" ));

与之对应的User实体类为:

1
2
3
4
5
6
7
8
9
10
11
public class User {
 
     private String userId;
     private String userName;
 
     public User(String userId, String userName) {
         this .userId = userId;
         this .userName = userName;
     }
 
}

感觉这种请求方式灵活性不是很高,需要通过传参来构造一个参数对象。没有@FormUrlEncoded 与 @FieldMap这种方式灵活。

1
2
3
4
Map queryBody =  new HashMap<>();
queryMap.put( "userId" "1001" );
queryMap.put( "userName" "kaikai" );
Call call = cityService.getCity(queryMap,queryBody);

请求网络数据的时候,以上是需要变化的地方,其他的地方保持不变。

4.常用配置

1.设置打印拦截器

 compile 'com.squareup.okhttp3:logging-interceptor:3.4.0-RC1'

首先添加依赖,进行log的打印

        HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
        logging.setLevel(HttpLoggingInterceptor.Level.BODY);

HttpLoggingInterceptor 是一个拦截器,用于输出网络请求和结果的 Log,可以配置 level 为 BASIC / HEADERS / BODY,查看源码它们级别依次是:

1
2
3
Logs request and response lines
Logs request and response lines and their respective headers
Logs request and response lines and their respective headers and bodies ( if present)

这里我们选择BODY即可,会打印出网络请求的url,头部信息headers,返回数据bodies所有信息

2.设置连接与读取超时

1
2
3
4
5
OkHttpClient okHttpClient =  new OkHttpClient.Builder()
          .connectTimeout( 30 , TimeUnit.SECONDS)
          .readTimeout( 30 , TimeUnit.SECONDS)
          .addInterceptor(logging)
          .build();

设置连接超时以及读取超时,然后将我们设置的拦截器添加进来。最后记得调用Retrofit.Builder()的.client(okHttpClient)方法,将我们已经设置好的okHttpClient关联好。

5.简单封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/**
  * Created by tangyangkai on 16/6/29.
  */
public class ApiWrapper {
 
     public static final String BASE_URL =  "http://111.111.1.11/" ;
     private Retrofit retrofit;
     private static ApiWrapper instance;
     private String token;
 
     private ApiWrapper() {
 
         HttpLoggingInterceptor logging =  new HttpLoggingInterceptor();
         logging.setLevel(HttpLoggingInterceptor.Level.BODY);
 
         OkHttpClient okHttpClient =  new OkHttpClient.Builder()
                 .connectTimeout( 30 , TimeUnit.SECONDS)
                 .readTimeout( 30 , TimeUnit.SECONDS)
                 .addInterceptor(logging)
                 .build();
 
         retrofit =  new Retrofit.Builder()
                 .baseUrl(BASE_URL)
                 .addConverterFactory(GsonConverterFactory.create())
                 .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                 .client(okHttpClient)
                 .build();
     }
 
     public static ApiWrapper getInstance() {
         if (instance ==  null ) {
             synchronized (ApiWrapper. class ) {
             if (instance ==  null ) {
                 instance =  new ApiWrapper();
                 }
             }
         }
         return instance;
     }
 
     public <T> T create(Class<T> services) {
         return retrofit.create(services);
     }
 
}

单例模式构建的一个ApiWrapper,这样就不用每次请求网络数据的时候去构建一个retrofit,使用的时候也很方便:

1
2
ApiService.CityService cityService = ApiWrapper.getInstance().create(ApiService.CityService. class );
Call call = cityService.getCity(queryMap);

其他的代码与前面的保持一致即可。

Retrofit的灵活与强大远不止这些,比如访问动态url,设置网络缓存,管理cookie,自定义转换器等,以后项目中有用到的地方再更新博客。我也是最近才从okHttp转战Retrofit的,博客有不当的地方欢迎指正。

你可能感兴趣的:(Android,Retrofit的简单使用)