初识Retrofit2.0

简介: 1.Retrofit简介 Retrofit无疑是当下最流行的Android网络请求框架了,是Square提供的开源产品。官方网站是这样介绍Retrofit的—-A type-safe HTTP client for Android and Java,为Android平台的应用提供一个类型安全的HTTP客户端。

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'

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

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

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

这里写图片描述

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

public class CityManager {

    private List<CityBean> cities;

    public List<CityBean> getCities() {
        return cities;
    }

    public void setCities(List<CityBean> 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完成数据请求的流程如下:

public class ApiService {

    public static final String RES_GET_CITIES_LIST = "Base/getCities";

    public interface CityService {
        @GET(RES_GET_CITIES_LIST)
        Call<CityManager> getCity
        (@QueryMap Map<String, String> queryMap);
    }

 }

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

Call<CityManager> getCity
(@Query("clientVersion") String clientVersion, @Query("version") String version);

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

    public static final String BASE_URL = "http://111.111.1.11/";
    Map<String, String> 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<CityManager> call = cityService.getCity(queryMap);
        call.enqueue(new Callback<CityManager>()
        {
            @Override
            public void onResponse(Call<CityManager> call, Response<CityManager> response)
            {
               ArrayList<String> cityNames = new ArrayList<>();
               ArrayList<String> cityIds = new ArrayList<>();
               for (CityManager.CityBean city : response.body().getCities()) {
                    cityNames.add(city.getName());
                    cityIds.add((city.getId()));
               }

            }

            @Override
            public void onFailure(Call<CityManager> call, Throwable t)
            {
              //进行异常情况处理
            }
        });

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

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

public class ApiService {

    public static final String RES_GET_CITIES_LIST = "Base/getCities";
    public interface CityService {
        @POST(RES_GET_CITIES_LIST)
        @FormUrlEncoded
        Call<CityManager> getCity
        (@QueryMap Map<String, String> queryMap,@FieldMap Map<String, String> queryBody);
    }

 }

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


Call<CityManager> getCity
(@QueryMap Map<String, String> queryMap, @Field("userId") String userId, @Field("userName") String userName);

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

 Call<CityManager> getCity(@QueryMap Map<String, String> queryMap, @Body User user);

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

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

与之对应的User实体类为:

public class User {

    private String userId;
    private String userName;

    public User(String userId, String userName) {
        this.userId = userId;
        this.userName = userName;
    }

}

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

    Map<String, String> queryBody = new HashMap<>();
    queryMap.put("userId", "1001");
    queryMap.put("userName", "kaikai");
    Call<CityManager> call = cityService.getCity(queryMapqueryBody);

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

3.动态请求url
请求城市的url:
http://111.111.1.11/Base/getCities/id/?clientVersion=205002&version=1622
假如其中的userId是动态变化的,请求方式为post,请求参数不变。那么我们的url也要进行变化:

public static final String RES_GET_CITIES_LIST = "Base/getCities/{id}/";

其中{id}可以理解为占位符,实际使用中会通过@Path注解对所标注的参数进行替换:

public interface CityService {
        @POST(RES_GET_CITIES_LIST)
        @FormUrlEncoded
        Call<CityManager> getCity
        (@Path("id") String id,@QueryMap Map<String, String> queryMap,@FieldMap Map<String, String> 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,查看源码它们级别依次是:

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.统一设置headers

Retrofit 2.0支持在每个请求方法的上面添加注解进行设置header:

@Headers("Content-Type: application/json")

但是这样的麻烦之处就是每次请求都得加上,所以就有了以下的方式:

        Interceptor interceptor = new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request request = chain.request()
                        .newBuilder()
                        .addHeader("Content-Type", "charset=UTF-8")
                        .addHeader("Connection", "keep-alive")
                        .build();
                return chain.proceed(request);
            }
        };

这里具体参数以服务器要求而定

3.设置连接与读取超时

       OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .addInterceptor(logging)
                .addInterceptor(interceptor)
                .build();

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

5.简单封装

/**
 * 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);


Interceptor interceptor = new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request request = chain.request()
                        .newBuilder()
                        .addHeader("Content-Type", "charset=UTF-8")
                        .addHeader("Connection", "keep-alive")
                        .build();
                return chain.proceed(request);
            }
        };


        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .addInterceptor(logging)
                .addInterceptor(interceptor)
                .build();

        retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.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,使用的时候也很方便:

ApiService.CityService cityService = ApiWrapper.getInstance().create(ApiService.CityService.class);
Call<CityManager> call = cityService.getCity(queryMap);

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

Retrofit的灵活与强大远不止这些,比如设置网络缓存,管理cookie,自定义转换器等,以后项目中有用到的地方再更新博客。

目录
相关文章
|
21天前
|
JSON Java 数据格式
rxjava2+retrofit2
rxjava2+retrofit2
27 1
|
9月前
|
缓存
Retrofit配置及各情况处理
Retrofit配置及各情况处理
163 0
|
JSON 安全 Java
Retrofit入门
Retrofit入门
|
设计模式 API
定制Retrofit
定制Retrofit
92 0
定制Retrofit
|
JSON Android开发 数据格式
RxJava+Retrofit示例 ,Retrofit 注解学习
RxJava+Retrofit示例 ,Retrofit 注解学习
122 0
|
API Android开发 Java
RxJava2 和 Retrofit2 结合使用详解
不讲 rxjava 和 retrofit 而是直接上手 2 了,因为 2 封装的更好用的更多。 1. 观察者模式 常见的 button 点击事件为例,button 是被观察者,listener 是观察者,setOnClickListener 过程是订阅,有了订阅关系后在 button 被点击的时候,监听者 listener 就可以响应事件。
|
JSON Java API
|
缓存 API Android开发
浅谈OkHttp以及Retrofit+RxJava的封装使用
1.为什么我们要使用OkHttp?OkHttp有什么优点?  说OkHttp之前我们先说另外两个网络请求库——HttpUrlConnection和HttpClient。
2155 0
|
Android开发 Java
|
Java Android开发 流计算