Android 浅谈Retrofit的封装
先了解Retrofit一般的使用步骤:
配置OkHttpClient,设置各种拦截器;
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183private volatile static OkHttpClient okHttpClient;
private volatile static Retrofit retrofit;
private static final int DEFAULT_CACHE_SIZE = 1024 * 1024 * 20;//默认缓存大小20M
private static final int DEFAULT_MAX_AGE = 60 * 60;// 默认缓存时间单位
private static final int DEFAULT_MAX_STALE_ONLINE = DEFAULT_MAX_AGE * 24;// 默认在线缓存时间
private static final int DEFAULT_MAX_STALE_OFFLINE = DEFAULT_MAX_AGE * 24 * 7;// 默认离线缓存时间
/**
* 保存cookies拦截器
*/
private static Interceptor SAVE_COOKIES_INTERCEPTOR = new Interceptor() {
public Response intercept(Chain chain) throws IOException {
SharedPreferences sharedPreferences = SuperRandyApplicationContext.context
.getSharedPreferences("cookie_sp", Context.MODE_PRIVATE);
Response originalResponse = chain.proceed(chain.request());
// 如果cookie为空,保存cookie到sp文件
if (CommonUtils.isNullOrEmpty(sharedPreferences.getString("cookie", ""))) {
// 获取请求返回的cookies
if (!CommonUtils.isNullOrEmpty(originalResponse.header("Set-Cookie")) &&
!originalResponse.header("Set-Cookie").isEmpty()) {
final StringBuffer cookieBuffer = new StringBuffer();
Observable.from(originalResponse.headers("Set-Cookie"))
.map(new Func1<String, String>() {
public String call(String s) {
String[] cookieArray = s.split(";");
return cookieArray[0];
}
})
.subscribe(new Action1<String>() {
public void call(String s) {
cookieBuffer.append(s).append(";");
}
});
KLog.e("save_cookie", cookieBuffer.toString());
// 保存cookies到sp文件
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("cookie", cookieBuffer.deleteCharAt(cookieBuffer.length() - 1).toString());
editor.apply();
}
}
return originalResponse;
}
};
/**
* 添加cookies拦截器
*/
private static Interceptor ADD_COOKIES_INTERCEPTOR = new Interceptor() {
public Response intercept(Chain chain) throws IOException {
final Request.Builder builder = chain.request().newBuilder();
SharedPreferences sharedPreferences = SuperRandyApplicationContext.context
.getSharedPreferences("cookie_sp", Context.MODE_PRIVATE);
Observable.just(sharedPreferences.getString("cookie", ""))
.subscribe(new Action1<String>() {
public void call(String s) {
builder.addHeader("Cookie", s);
}
});
KLog.e("add_cookie", sharedPreferences.getString("cookie", ""));
return chain.proceed(builder.build());
}
};
/**
* request 拦截器定义
*/
private static final Interceptor REQUEST_INTERCEPTOR = new Interceptor() {
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
int maxStale = DEFAULT_MAX_STALE_ONLINE;
//向服务期请求数据缓存1个小时
CacheControl tempCacheControl = new CacheControl.Builder()
// .onlyIfCached()
.maxStale(5, TimeUnit.SECONDS)
.build();
request = request.newBuilder()
.cacheControl(tempCacheControl)
.build();
return chain.proceed(request);
}
};
/**
* response 拦截器定义
*/
private static final Interceptor RESPONSE_INTERCEPTOR = new Interceptor() {
public Response intercept(Chain chain) throws IOException {
//针对那些服务器不支持缓存策略的情况下,使用强制修改响应头,达到缓存的效果
//响应拦截只不过是出于规范,向服务器发出请求,至于服务器搭不搭理我们我们不管他,我们在响应里面做手脚,有网没有情况下的缓存策略
Request request = chain.request();
Response originalResponse = chain.proceed(request);
int maxAge;
// 缓存的数据
if (!NetworkUtils.isConnected(SuperRandyApplicationContext.context)) {
maxAge = DEFAULT_MAX_STALE_OFFLINE;
} else {
maxAge = DEFAULT_MAX_STALE_ONLINE;
}
return originalResponse.newBuilder()
.removeHeader("Pragma")// 清除头信息,因为服务器如果不支持,会返回一些干扰信息,不清除下面无法生效
.removeHeader("Cache-Control")
.header("Cache-Control", "public, max-age=" + maxAge)
.build();
}
};
/**
* 打印返回的json数据拦截器
*/
private static final Interceptor LOGGING_INTERCEPTOR = new Interceptor() {
public Response intercept(Chain chain) throws IOException {
final Request request = chain.request();
final Response response = chain.proceed(request);
final ResponseBody responseBody = response.body();
final long contentLength = responseBody.contentLength();
BufferedSource source = responseBody.source();
source.request(Long.MAX_VALUE); // Buffer the entire body.
Buffer buffer = source.buffer();
Charset charset = Charset.forName("UTF-8");
MediaType contentType = responseBody.contentType();
if (contentType != null) {
try {
charset = contentType.charset(charset);
} catch (UnsupportedCharsetException e) {
KLog.e("");
KLog.e("Couldn't decode the response body; charset is likely malformed.");
return response;
}
}
if (contentLength != 0) {
long t1 = System.nanoTime();
Log.i("OkHttp:", String.format("Sending %s request %s on %s%n%s", request.method(), request.url(), chain.connection(), request.headers()));
long t2 = System.nanoTime();
Log.i("OkHttp:", String.format("Received response for %s in %.1fms%n%s", response.request().url(), (t2 - t1) / 1e6d, response.headers()));
KLog.v("--------------------------------------------开始打印返回数据----------------------------------------------------");
KLog.json(buffer.clone().readString(charset));
KLog.v("--------------------------------------------结束打印返回数据----------------------------------------------------");
}
return response;
}
};
/**
* 获取OkHttpClient实例
*
* @return OkHttpClient实例
*/
private static OkHttpClient getOkHttpClient() {
if (okHttpClient == null) {
synchronized (OkHttpClient.class) {// 同步访问
if (okHttpClient == null) {
// 网络请求相关缓存
File cacheFile = new File(SuperRandyApplicationContext.application.getCacheDir(), "responses");
Cache cache = new Cache(cacheFile, DEFAULT_CACHE_SIZE);
okHttpClient = new OkHttpClient.Builder()
.cache(cache)
// 添加相关拦截器
.addInterceptor(SAVE_COOKIES_INTERCEPTOR)
.addInterceptor(ADD_COOKIES_INTERCEPTOR)
.addNetworkInterceptor(RESPONSE_INTERCEPTOR)
.addInterceptor(REQUEST_INTERCEPTOR)
.addInterceptor(LOGGING_INTERCEPTOR)
.build();
}
}
}
return okHttpClient;
}
配置Retrofit实例,主要是client;
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/**
* 获取OkHttpClient实例
*
* @return OkHttpClient实例
*/
private static OkHttpClient getOkHttpClient() {
if (okHttpClient == null) {
synchronized (OkHttpClient.class) {// 同步访问
if (okHttpClient == null) {
// 网络请求相关缓存
File cacheFile = new File(SuperRandyApplicationContext.application.getCacheDir(), "responses");
Cache cache = new Cache(cacheFile, DEFAULT_CACHE_SIZE);
okHttpClient = new OkHttpClient.Builder()
.cache(cache)
// 添加相关拦截器
.addInterceptor(SAVE_COOKIES_INTERCEPTOR)
.addInterceptor(ADD_COOKIES_INTERCEPTOR)
.addNetworkInterceptor(RESPONSE_INTERCEPTOR)
.addInterceptor(REQUEST_INTERCEPTOR)
.addInterceptor(LOGGING_INTERCEPTOR)
.build();
}
}
}
return okHttpClient;
}定义Service接口类,如
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public interface User {
Observable<Response<BaseResponse<LoginResultBean>>> login( String username,
; String psw)
Observable<Response<BaseResponse<Object>>> logout();
Observable<Response<BaseResponse<Boolean>>> isRegistered(; String mobile)
}
获取Retrofit实例;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21/**
* 获取retrofit实例
*
* @param baseUrl baseURL
* @return retrofit实例
*/
public static Retrofit getRetrofit(String baseUrl) {
if (retrofit == null) {
synchronized (Retrofit.class) {
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.client(getOkHttpClient())
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
}
}
}
return retrofit;
}创建Service,并访问接口
1
getRetrofit("http://local.rainmonth.com").create(User.class).login("mobile", "password");
处理返回结果。
封装所需要的功能
- 采用现在流行的链式结构进行创建;
- 提供一个接口形式的ApiService即可完成各种请求;
- 提供必要的回调函数处理返回结果;
- 提供通用的接收返回数据的容器;
- 支持多文件上传下载,并提供进度显示;(Download and upload)
- 可以动态配置;(Config)
- 良好的容错处理,能对返回结果进行统一处理和差异性处理;(网络错误,通用异常)(Exception and Error)
- Cookies持久化处理;(Cookie)
- 数据的缓存功能;(Cache,不同的缓存方式:内存,SD卡,数据库)
- 支持请求的取消,支持同步请求、支持异步请求;(方便调用get、post方法)
- 支持请求数据的拦截(方便后期调试)