作为一枚android程序员,处理API数据接口可谓家常便饭,既然是一项不可少的事,那就把它做好。本篇博客的内容也是我近期做的项目中模块的一隅,代码组织的好与不好暂且不论,首先解决问题才是最应该被关注的,当然如果同学们有好的意见也随时跟我沟通。我先声明这篇博客不会去分析某个网络请求框架,也不会从头开始写一个网络请求框架,我们应该注重实效,并不是我不建议同学去分析某个知名的框架,恰恰相反我很鼓励同学们去分析精品框架源码并尝试写一些框架。不罗嗦了,下面进入本文正题。
制定规约
首先要明白一点,我们客户端从提供数据的后台请求数据的规约必须先明确之,其中包括是采用SOAP Webservice还是Restful Webservice,采用XML协议作为数据交换格式还是采用JSON协议作为数据交换格式,接口返回的数据结构是什么样子的,具体每一个接口请求方式是什么。我目前的项目是采用Restful Webservice,交换数据格式为JSON。接口返回数据统一格式是这样的:
{
status:xxx
msg:xxx
result:xxx
}
当然这些数据是在一次请求成功后才能获得,先不考虑获取不到数据的情况,请求异常情况后文再做进一步探讨;status表明一次请求的状态,一般是指业务层级上的状态值,msg记录一次请求的说明信息文本,可直接在UI显示(建议采用这种方式,可后台灵活配置),result存储某一次请求所返回的业务实体或者业务实体集合,当然也有例外,暂且不议。
解决方案
既然已经和后台制定好了规约,那接下来的工作就是客户端如果实施的问题。网络请求框架本文采用Square开源的Retrofit框架,对它还比较陌生的同学请阅读一下说明文档,接口返回数据解析采用的Google开源的Gson框架;关于如何配置Retrofit,我想同学同学们心里都有一个考量标准,以下是我目前项目的使用Retrofit的具体配置:
@Singleton
public class ApiConnector {
private final Interceptor mSignInterceptor;
private Retrofit mRetrofit;
private OkHttpClient okHttpClient;
@Inject
public ApiConnector(Interceptor signInterceptor) {
mSignInterceptor = signInterceptor;
init();
}
private void init() {
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
okHttpClient = getHttpBuilder()
.addInterceptor(loggingInterceptor)
.addInterceptor(mSignInterceptor)
.connectTimeout(NetworkConfig.REQUEST_TIME_OUT_DURATION, TimeUnit.SECONDS)
.build();
mRetrofit = new Retrofit.Builder()
.baseUrl(getApiBaseUrl())
.client(okHttpClient)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(new Gson()))
.build();
}
protected OkHttpClient.Builder getHttpBuilder() {
return new OkHttpClient.Builder();
}
protected String getApiBaseUrl() {
return NetworkConfig.BASE_API_URL;
}
public Retrofit getApiCreator() {
return mRetrofit;
}
}
首先构造函数中我们传入Interceptor某个实现对象,看到对象名signInterceptor就应该能猜到它是对请求进一步签名,接着分析init/0函数,在函数中我们又定义一个HttpLoggingInterceptor对象,看类名就该知道它是一个Http request日志拦截器,升级版的Retrofit2具有更高的可配置性,可将OkHttp作为Retrofit的Request client,OkHttp提供可配置的拦截器,HttpLoggingInterceptor是OkHttp提供的也可根据具体需求自定义实现,处理结果大致是这样的:
我想多半app都会收集一些用户的信息,我项目中叫做KPI,我项目中是通过自定义拦截器做统一收集,也就是前文提到的SignInterceptor,具体实现如下:
@Singleton
public final class SigningInterceptor implements Interceptor {
private Context mContext;
private AccountEntity mAccountEntity;
private AuthToken mAuthToken;
@Inject
AccountCache mAccountCache;
@Inject
AuthTokenCache mAuthTokenCache;
@Inject
SigningInterceptor(Context context) {
mContext = context.getApplicationContext();
}
@Override
public Response intercept(Chain chain) throws IOException {
if (null == mAccountEntity)
mAccountEntity = mAccountCache.get();
if (null == mAuthToken)
mAuthToken = mAuthTokenCache.getAuthToken();
Request originalRequest = chain.request();
Request.Builder requestBuilder = originalRequest.newBuilder()
.addHeader(ParamConstants.KPI.CLIENT_TYPE, ParamConstants.Value.CLIENT)
.addHeader(ParamConstants.KPI.FIRST_SRC, ClientUtil.getFirstSrc(mContext
, ParamConstants.KPI.CHANNEL_PLACE_HOLDER))
.addHeader(ParamConstants