Rxjava
优点:基于事件流的链式调用,逻辑简洁,使用简单
引入
简单看一下Rxjava 一般使用方式
//观察者
Observable.create(new ObservableOnSubscribe(){
@Override
public void subscribe(ObservableEmitter emitter) throws Exception {
//ObservableEmitter emitter 被观察者
//数据改变者
}
}).
//订阅者
subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Object o) {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
说明:
Observable创建需要ObservableOnSubscribe接口
当调用subscribe时 根据observer 创建ObservableEmitter 发射器
emitter反射器回调 observer中的方法
map和flatmap
map:返回的是结果集,只能单一转换,每传递一个事件执行一次onNext方法
flatmap:返回Observable,可以多对多 一对多,一对一转换 一般利用from/just进行分发
操作符
1 interval:创建一个按固定时间间隔发射整数序列的Observable
Observable.interval(3, TimeUnit.SECONDS).subscribe(new Consumer<Long>() {
@Override
public void accept(Long aLong) throws Exception {
Log.e("zgt", String.valueOf(aLong));
}
});
每隔3秒调用一次
2 range 发射指定范围的整数 可以拿了替换for循环
Observable.range(0, 10).subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log.e("zgt", String.valueOf(integer));
}
});
3 repeat 创建一个N次重复发射特定数据的Observable
Observable.range(0,3).repeat(2).subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
System.out.println(integer);
}
});
变换操作符
1 map 将Obserable 转换为一个新的Obserable
Observable.just("abc").map(r->r.substring(0,1)).subscribe((t)->{
System.out.println(t);
});
2 flatMap,cast flatMap 将Observable 发射的数据集合 变换为新的Observable集合,可以多对多 一对多,一对一转换 一般利用from/just进行分发。cast 强制将Obserable发射的数据转换为指定的类型
Observable.fromIterable(Arrays.asList("abc","zgt","hello")).flatMap(new Function<String, ObservableSource<?>>() {
@Override
public ObservableSource<?> apply(String s) throws Exception {
return Observable.fromArray("a","b",s);
}
}).subscribe(t->{
System.out.println(t);
});
3 concatMap 和flatMap 一样 解决了flatMap交叉问题
如果想要最后输出的事件顺序和源数据的顺序一致只要换成concatMap就可以了
Observable.fromIterable(Arrays.asList("abc","zgt","hello")).concatMap(new Function<String, ObservableSource<?>>() {
@Override
public ObservableSource<?> apply(String s) throws Exception {
return Observable.fromArray("a","b",s);
}
}).subscribe(t->{
System.out.println(t);
});
4 flatMapIterable将数据包装成Iterable
Observable.just(1,2,3,4).flatMapIterable(new Function<Integer, Iterable<?>>() {
@Override
public Iterable<?> apply(Integer integer) throws Exception {
return Arrays.asList(integer+1);
}
}).subscribe(t->{
System.out.println(t);
});
5 buffer 将Observable变换为一个新的Observable 这个新的Observable每次发射一组列表
Observable.just(1,2,3,4,5,6).buffer(4).subscribe(new Consumer<List<Integer>>() {
@Override
public void accept(List<Integer> integers) throws Exception {
System.out.println(integers);
}
});
6 groupBy 分组 将源Observable变换成新的Observable 它们中的每一个新的Observable都发射一组指定的数据
Observable<GroupedObservable<String, String>> groupedObservableObservable = Observable.just( "bxxx","abc", "abd", "azzz", "bvvv").groupBy(t -> t.substring(0, 1));
Observable.concat(groupedObservableObservable).subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
System.out.println(s);
}
});
过滤操作符
1 filter 对Observable产生的数据结果进行过滤只有满足条件的结果才交给订阅者
Observable.just(1,2,3,4).filter(t->t%2==0).subscribe(t->{
System.out.println(t);
});
2 elementAt 用来返回指定位置的数据
Observable.just(1,2,3,4).elementAt(2).subscribe(t->{
System.out.println(t);
});
3 distinct 去重
Observable.just(1,2,1,2,3,1,1,1,1,1).distinct().subscribe(t->{
System.out.println(t);
});
4 skip, take skip 将源Observable数据过滤掉前n项 take 只取前N项
Observable.just(1,2,3,4,5,6,7).skip(3).subscribe(t->{
System.out.println(t);
});
Observable.just(1,2,3,4,5,6,7).take(3).subscribe(t->{
System.out.println(t);
});
5 ignoreElements 忽略Observable产生的结果
Observable.just(1,2,3,4,5,6,7).ignoreElements().subscribe();
6 throttleFirst 定期发射这个时间段里Observable的第一个数据
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
for (int i = 0; i <10 ; i++) {
emitter.onNext(i);
Thread.sleep(100);
}
}
}).throttleFirst(200,TimeUnit.MILLISECONDS).subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
System.out.println(integer);
}
});
组合操作符
1 startWith 在Observable发射的数据前面加上一些数据
Observable.just(3,4,5).startWith(1).startWithArray(1,2,6).subscribe(t->{
System.out.println(t);
});
2 merge 将多个Observable合并到一个Observable发射数据交错
Observable<Integer> obs1 = Observable.just(1, 2, 3).subscribeOn(Schedulers.io());
Observable<Integer> obs2 = Observable.just(4,5,6);
Observable.merge(obs1,obs2).subscribe(t->{
System.out.println(t);
});
3 concat 将多个Observable 发射的数据进行合并发射 concat严格按照顺序发射数据,前一个observable没有完成不会发射下一个observable
Observable.concat(obs1,obs2).subscribe(t->{
System.out.println(t);
});
4 zip 合并两个或者多个Observable发射出数据项 根据指定的函数变换它们并发射一个新值
Observable<Integer> o1 = Observable.just(1, 2, 3);
Observable<String> o2 = Observable.just("a","b","c","d");
Observable.zip(o1, o2, (t1,t2)->String.valueOf(t1)+String.valueOf(t2))
.subscribe(t->{
System.out.println(t);
});
5 combineLastest 类似zip 区别 o1 最后元素 与 o2没有元素合并
Observable<Integer> o1 = Observable.just(1, 2, 3,4);
Observable<String> o2 = Observable.just("a","b","c");
Observable.combineLatest(o1, o2, (t1,t2)->String.valueOf(t1)+String.valueOf(t2))
.subscribe(t->{
System.out.println(t);
});
辅助操作符
1 delay 在发射数据之前都暂停一段时间
Observable.just(1,2,3,4,5).delay(2,TimeUnit.SECONDS).subscribe(t->{
System.out.println(t);
});
2 Do 为原始Observable的生命周期事件注册一个回调
1, doOnEach: 当Observable 每发射一项数据就会调用它一次 包括onNext onError onCompleted
2,doOnNExt:只有执行onNext的时候会调用
3,doOnSubscribe:当观察者订阅Observable时调用
4,doOnUnsubscribe:当观察者取消订阅时调用
5,doOnCompleted:当Observable正常终止调用onCompleted 会调用
6,doOnError:当Observable异常终止调用onError时会被调用
7,doOnTerminate:当Observable终止(无论正常还是异常)之前会被调用
8,finallyDo:当Observable终止(无论正常还是异常)之后会被调用
```java
Observable.just(1,2,3,4).doOnNext(t->{
System.out.println(t);
}).subscribe(new Observer() {
@Override
public void onSubscribe(Disposable disposable) {
System.out.println(“onSubscribe”);
}
@Override
public void onNext(Integer integer) {
System.out.println("onNext");
}
@Override
public void onError(Throwable throwable) {
System.out.println("onError");
}
@Override
public void onComplete() {
System.out.println("onComplete");
}
});
```
3 subscribeOn,observeOn
subscribeOn:指定Observable在哪个线程上运行
observeOn:指定Observable所运行的线程,也就是发射出的数据在哪个线程上使用
Observable<Integer> observable = Observable.create(new ObservableOnSubscribe(){
@Override
public void subscribe(ObservableEmitter observableEmitter) throws Exception {
System.out.println(Thread.currentThread().getName());
observableEmitter.onNext(1);
observableEmitter.onNext(2);
observableEmitter.onComplete();
}
});
observable.subscribeOn(Schedulers.newThread()).observeOn(Schedulers.single()).subscribe(t->{
System.out.println(Thread.currentThread().getName());
System.out.println(t);
});
4 timeout :原始Observable过了指定时间没有发射任何数据 timeout会以一个onError通知这个Observable终止或者继续执行一个备用的Observable
Observable<Integer> obs3 = Observable.create(new ObservableOnSubscribe(){
@Override
public void subscribe(ObservableEmitter observableEmitter) throws Exception {
Thread.sleep(2000);
observableEmitter.onNext(2);
}
});
obs3.timeout(1,TimeUnit.SECONDS,Observable.just(3)).subscribe(new Observer<Integer>() {
@Override
public void onSubscribe(Disposable disposable) {
//System.out.println("onSubscribe");
}
@Override
public void onNext(Integer integer) {
System.out.println("onNext");
}
@Override
public void onError(Throwable throwable) {
System.out.println("onError");
}
@Override
public void onComplete() {
// System.out.println("onComplete");
}
});
错误处理操作符
1 catch :拦截原始Observable的onError通知,将它替换为其它数据项或数据序列
1,onErrorReturn:当Observable遇到错误时返回原有Observable行为备用的Observable,会忽略原有的Observable的onError回调
2,onErrorResumeNext:
3,onErrorResumeNext:
4,onExceptionResumeNext:
Observable o4 = Observable.create(new ObservableOnSubscribe(){
@Override
public void subscribe(ObservableEmitter emitter) throws Exception {
//emitter.onNext(1);
emitter.onError(new Throwable("error"));
}
});
// Observable o5 = o4.onErrorReturn(new Function() {
// @Override
// public Object apply(Object o) throws Exception {
// System.out.println(">>>>"+ o.toString());
// return "zgt";
// }
// });
Observable o5 = o4.onErrorResumeNext(new ObservableSource(){
@Override
public void subscribe(Observer observer) {
observer.onNext(3);
}
});
o5.subscribe(new Observer() {
@Override
public void onSubscribe(Disposable disposable) {
System.out.println("onSubscribe");
}
@Override
public void onNext(Object o) {
System.out.println("onNext");
}
@Override
public void onError(Throwable throwable) {
System.out.println("onError");
}
@Override
public void onComplete() {
System.out.println("onComplete");
}
});
2 retry :将原始Observable 发射了错误 retry 会重新发射数据重复n次 到onNext 这个可能造成数据重复
Observable o5 = o4.retry(3);
条件操作符和布尔操作符
布尔操作符
1 all 根据一个函数对源Observable 发射的所有数据进行判断
Observable.just(1,2,3,4).all(new Predicate<Integer>() {
@Override
public boolean test(Integer integer) throws Exception {
System.out.println(integer);
return integer<3;
}
}).subscribe(t->{
System.out.println(t);
});
2,contains ,isEmpty
contains:判断Obaservable 发射的数据中是否包含某个数据如果包含返回 true
isEmpty:判断Observable是否发射过数据
Observable.just(1,2,3).contains(2).subscribe(t->{
System.out.println(t);
});
Observable.just(1,2,3).isEmpty().subscribe(t->{
System.out.println(t);
});
条件操作符
条件操作符有 amb , defaultIfEmpty,skipUntil,skipWhile,takeUntil,takeWhile 等
1 amb 对于给定的两个Observable 它只发射首先发射的Observable
Observable.ambArray(Observable.just(1,2),Observable.just(3,4,5)).subscribe(t->{
System.out.println(t);
});
2 defaultIfEmpty 发射原始Observable 如果原始的Observable没有数据 就发射一个默认数据
Observable.create(new ObservableOnSubscribe(){
@Override
public void subscribe(ObservableEmitter emitter) throws Exception {
emitter.onComplete();
}
} ).defaultIfEmpty(3).subscribe(t->{
System.out.println(t);
});
转换操作符
1,toList :发射多项数据合并成一个List 然后调用一次onNext方法传递整个列表
Observable.just(1,2,4).toList().subscribe(t->{
System.out.println(t);
});
2,toSortedList 类似toList 它会对产生的列表排序
Observable.just(3,1,4,8).toSortedList().subscribe(t->{
System.out.println(t);
});
3,toMap 搜集原始Observable数据发射到一个map中(默认HashMap)
Observable.just(1,2,3).toMap(new Function(){
@Override
public Object apply(Object o) throws Exception {
return "key_"+o;
}
}).subscribe(t->{
System.out.println(t);
});
RxJava 线程控制
1,内置的调度器Scheduler
1,Schedulers.trampoline( ) 直接在当前线程运行
Observable.just(1,2,3).subscribeOn(Schedulers.trampoline()).subscribe(t->{
System.out.println(Thread.currentThread().getName());
});
2,Schedulers.newThread() 总是启用新的线程
Observable.just(1,2,3).subscribeOn(Schedulers.newThread()).subscribe(t->{
System.out.println(Thread.currentThread().getName());
});
3,Schedulers.io() I/O 操作 内部实现是用一个无数量上限的线程池,可以重用空闲的线程池,因此io比newThread更有效率
Observable.just(1,2,3).subscribeOn(Schedulers.io()).subscribe(t->{
System.out.println(Thread.currentThread().getName());
});
4,Schedulers.computation() 计算所使用的线程池 例如图形的计算 内部使用了固定的线程池,大小为cpu核数
不要把io操作放到computation中否则io的操作等待浪费cpu。他是buffer debounce delay interval sample 和 skip 操作符的默认调度器
Observable.just(1,2,3).subscribeOn(Schedulers.computation()).subscribe(t->{
System.out.println(Thread.currentThread().getName());
});
5,AndroidSchedulers.mainThread(): android 中切换到主线程
2,控制线程
使用 subscribeOn和observeOn 操作符来控制线程
subscribeOn:用于该操作符之前的 Observable
observeOn:用于该操作符之后的 Observable
OKhttp
基本用法
1,最简单的get请求
Request.Builder builder = new Request.Builder();
builder.url("http://www.baidu.com");
builder.method("GET",null);
Request request=builder.build();
OkHttpClient client = new OkHttpClient();
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String str = response.body().string();
System.out.println(str);
}
});
2,异步post 请求
RequestBody formBody = new FormBody.Builder()
.add("ip","59.108.54.37")
.build();
Request request = new Request.Builder()
.url("http://ip.taobao.com/service/getIpInfo.php")
.post(formBody)
.build();
OkHttpClient client = new OkHttpClient();
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String str = response.body().string();
System.out.println(str);
}
});
3,异步上传文件
MediaType markdown = MediaType.parse("text/x-markdown; charset=utf-8");
File file = new File("xxxx.txt");
Request request = new Request.Builder()
.url("http://xxxxx")
.post(RequestBody.create(markdown,file))
.build();
OkHttpClient client = new OkHttpClient();
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String str = response.body().string();
System.out.println(str);
}
});
4,异步下载文件
Request request = new Request.Builder()
.url("https://ss0.baidu.com/6ONWsjip0QIZ8tyhnq/it/u=423512187,2285661156&fm=173&app=25&f=JPEG?w=640&h=320&s=9FA0E9044ECA972C0CECA1D30100C0B1")
.build();
OkHttpClient client = new OkHttpClient();
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
InputStream in = response.body().byteStream();
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte []bytes = new byte[1024];
int len =0;
while ((len = in.read(bytes))>0){
out.write(bytes, 0, len);
}
in.close();
out.flush();
byte[] bytes1 = out.toByteArray(); //图片数据
out.close();
}
});
6 异步上传Multipart 文件
MediaType mediaPng = MediaType.parse("image/png");
OkHttpClient client = new OkHttpClient();
RequestBody requestBody = new MultipartBody.Builder()
.setType(mediaPng)
.addFormDataPart("title","xxx" )
.addFormDataPart("image", "xxx.png",RequestBody.create(mediaPng, new File("/sdcard/xxx.png")))
.build();
Request request = new Request.Builder()
.header("Authorization", "Client-ID")
.url("https://api.imgur.com/3/image")
.post(requestBody)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
System.out.println(response.body().string());
}
});
6 设置超时时间和缓存
File sdcache = context.getExternalCacheDir();
int cacheSize = 10 * 1024 *1024;
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS)
.readTimeout(20,TimeUnit.SECONDS )
.cache(new Cache(sdcache, cacheSize))
.build();
7,取消请求
Request request = new Request.Builder()
.url("http://www.baidu.com")
.cacheControl(CacheControl.FORCE_NETWORK)
.build();
OkHttpClient client = new OkHttpClient();
Call call = client.newCall(request);
//取消请求
call.cancel();
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (null != response.cacheResponse()){
System.out.println(response.cacheResponse().toString());
}else {
System.out.println(response.networkResponse().toString());
}
}
});
源码解析
异步请求
request->Client->RealCall->Dispatcher->Async->ThreadPool->InterceptorChain->Response
同步请求
request->Client->RealCall->Dispatcher->Sync->InterceptorChain->Response
1,OkHttp请求网络流程
call=client.newCall(request);
call.enqueue(new Callback())
newCall 返回给我们的是RealCall 然后调用RealCall的enqueue方法
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
可以看到最终是有dispatcher来完成的
2,Dispatcher 任务调度
//最大并非请求
private int maxRequests = 64;
//每个主机最大请求数
private int maxRequestsPerHost = 5;
private @Nullable Runnable idleCallback;
/** 消费者线程池 */
private @Nullable ExecutorService executorService;
/** 将要运行的请求队列 */
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
/** 正在运行的异步请求队列 */
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
/** 正在运行的同步请求队列 */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
构造方法
public Dispatcher(ExecutorService executorService) {
this.executorService = executorService;
}
public Dispatcher() {
}
//默认创建的线程池
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
默认的线程池比较适合执行大量的耗时,任务比较少的情况
也可以自定义线程池
synchronized void enqueue(AsyncCall call) {
//当前运行的异步请求队列中数量小于64 并且正在运行的请求主机小于5时 把请求加载到runningAsynCalls进行缓存等待
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
参数AsyncCall 是RealCall内部类 实现了Runable接口 实现execute方法
RealCall 实现的execute方法
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain(); //请求网络中的数据
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
eventListener.callFailed(this, e);
throw e;
} finally {
//无论如何都要调用 dispatcher的finished 方法 通知下一个 让下个来运行
client.dispatcher().finished(this);
}
}
Dispatcher 的finished方法中调用promoteCalls方法
private void promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);
executorService().execute(call);
}
if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
}
}
从readyAsyncCalls 队列中取出 来执行
3,Iinterceptor 拦截器
使用责任链模式:例如请假,A 向领导B请假 B 说我去找我的领导C 领导 C 找领导D
D 告诉C同意 C告诉B 好,同意 B告诉A 同意你了 A拿到了结果数据 同意你了 可以对数据加工
Response result = getResponseWithInterceptorChain(); //请求网络中的数据
源码
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());//添加自定义的拦截器
interceptors.add(retryAndFollowUpInterceptor);
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);
}
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
// If we already have a stream, confirm that the incoming request will use it.
if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must retain the same host and port");
}
// If we already have a stream, confirm that this is the only call to chain.proceed().
if (this.httpCodec != null && calls > 1) {
throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
+ " must call proceed() exactly once");
}
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
// Confirm that the next interceptor made its required call to chain.proceed().
if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
throw new IllegalStateException("network interceptor " + interceptor
+ " must call proceed() exactly once");
}
// Confirm that the intercepted response isn't null.
if (response == null) {
throw new NullPointerException("interceptor " + interceptor + " returned null");
}
if (response.body() == null) {
throw new IllegalStateException(
"interceptor " + interceptor + " returned a response with no body");
}
return response;
}
拦截器:是一种能够监控,重写,重试调用的机制。通常情况下用来添加,移除,转换请求 和响应头部信息。例如将域名替换为ip地址,在请求头上添加host属性等等
4, 缓存策略
CacheInterceptor 缓存拦截器
//缓存文件夹
File cacheFile = new File(getExternalCacheDir().toString(),"cache");
//缓存大小为10M
int cacheSize = 10 * 1024 * 1024;
//创建缓存对象
Cache cache = new Cache(cacheFile,cacheSize);
OkHttpClient client = new OkHttpClient.Builder()
.cache(cache)
.build();
缓存根据响应头 Cache-Control:max-age=60 来决定缓存多长时间,如果响应头不存在Cache-Control:max-age=60 可以自定义拦截器修改响应头
class CacheInterceptor implements Interceptor{
@Override
public Response intercept(Chain chain) throws IOException {
Response originResponse = chain.proceed(chain.request());
//设置缓存时间为60秒,并移除了pragma消息头,移除它的原因是因为pragma也是控制缓存的一个消息头属性
return originResponse.newBuilder().removeHeader("pragma")
.header("Cache-Control","max-age=60").build();
}
}
//缓存文件夹
File cacheFile = new File(getExternalCacheDir().toString(),"cache");
//缓存大小为10M
int cacheSize = 10 * 1024 * 1024;
//创建缓存对象
final Cache cache = new Cache(cacheFile,cacheSize);
OkHttpClient client = new OkHttpClient.Builder()
.addNetworkInterceptor(new CacheInterceptor())
.cache(cache)
.build();
okhttp官方文档建议缓存方法
//缓存文件夹
File cacheFile = new File(getExternalCacheDir().toString(),"cache");
//缓存大小为10M
int cacheSize = 10 * 1024 * 1024;
//创建缓存对象
final Cache cache = new Cache(cacheFile,cacheSize);
OkHttpClient client = new OkHttpClient.Builder()
.cache(cache)
.build();
//设置缓存时间为60秒
CacheControl cacheControl = new CacheControl.Builder()
.maxAge(60, TimeUnit.SECONDS)
.build();
Request request = new Request.Builder()
.url("http://blog.youkuaiyun.com/briblue")
.cacheControl(cacheControl)
.build();
Cache 类
Cache(File directory, long maxSize, FileSystem fileSystem) {
this.cache = DiskLruCache.create(fileSystem, directory, VERSION, ENTRY_COUNT, maxSize);
}
在Cache类的构造方法中创建了DiskLruCache类型的cache 实例,这里的FileSystem.SYSTEM是FileSystem(文件系统接口)的实现,其内部是基于Okio的sink/source对缓存文件进行流操作。在DiskLruCache.Entry内部维护了两个数组,保存每个url请求对应文件的引用。然后通过DiskLruCache.Editor操作DiskLruCache.Entry中的数组,并为Cache.Entry提供Sink/source,对文件流进行操作。这点会在后续分析Cache的put和get中证实。
5,失败重连
RetryAndFollowUpInterceptor 失败重试拦截器
用于创建StreamAllocation 能重试21次或者取消退出
@Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
RealInterceptorChain realChain = (RealInterceptorChain) chain;
Call call = realChain.call();
EventListener eventListener = realChain.eventListener();
StreamAllocation streamAllocation = new StreamAllocation(client.connectionPool(),
createAddress(request.url()), call, eventListener, callStackTrace);
this.streamAllocation = streamAllocation;
int followUpCount = 0;
Response priorResponse = null;
while (true) {
if (canceled) {
streamAllocation.release();
throw new IOException("Canceled");
}
Response response;
boolean releaseConnection = true;
try {
response = realChain.proceed(request, streamAllocation, null, null);
releaseConnection = false;
} catch (RouteException e) {
// The attempt to connect via a route failed. The request will not have been sent.
if (!recover(e.getLastConnectException(), streamAllocation, false, request)) {
throw e.getLastConnectException();
}
releaseConnection = false;
continue;
} catch (IOException e) {
// An attempt to communicate with a server failed. The request may have been sent.
boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
if (!recover(e, streamAllocation, requestSendStarted, request)) throw e;
releaseConnection = false;
continue;
} finally {
// We're throwing an unchecked exception. Release any resources.
if (releaseConnection) {
streamAllocation.streamFailed(null);
streamAllocation.release();
}
}
// Attach the prior response if it exists. Such responses never have a body.
if (priorResponse != null) {
response = response.newBuilder()
.priorResponse(priorResponse.newBuilder()
.body(null)
.build())
.build();
}
Request followUp = followUpRequest(response, streamAllocation.route());
if (followUp == null) {
if (!forWebSocket) {
streamAllocation.release();
}
return response;
}
closeQuietly(response.body());
if (++followUpCount > MAX_FOLLOW_UPS) {
streamAllocation.release();
throw new ProtocolException("Too many follow-up requests: " + followUpCount);
}
if (followUp.body() instanceof UnrepeatableRequestBody) {
streamAllocation.release();
throw new HttpRetryException("Cannot retry streamed HTTP body", response.code());
}
if (!sameConnection(response, followUp.url())) {
streamAllocation.release();
streamAllocation = new StreamAllocation(client.connectionPool(),
createAddress(followUp.url()), call, eventListener, callStackTrace);
this.streamAllocation = streamAllocation;
} else if (streamAllocation.codec() != null) {
throw new IllegalStateException("Closing the body of " + response
+ " didn't close its backing stream. Bad interceptor?");
}
request = followUp;
priorResponse = response;
}
}
OkHttp复用连接池
Http中有一种叫keep alive connections 的机制;okhttp支持5个并发socket连接 默认keepalive时间为5分钟
ConnectionPool
private static final Executor executor = new ThreadPoolExecutor(0 /* corePoolSize */,
Integer.MAX_VALUE /* maximumPoolSize */, 60L /* keepAliveTime */, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp ConnectionPool", true));
//最大空闲socket最大连接数
private final int maxIdleConnections;
//socket的keepAlive时间
private final long keepAliveDurationNs;
//双向队列 经常在缓存中使用 RealConnection socket物理连接
private final Deque<RealConnection> connections = new ArrayDeque<>();
//用来记录连接失败的路线名单,当连接失败的时候就把失败的线路加进去
final RouteDatabase routeDatabase = new RouteDatabase();
public ConnectionPool() {
//空闲socket5个 keepAlive时间5分钟
this(5, 5, TimeUnit.MINUTES);
}
executor 线程池采用了没有容量的SynchronousQueue
缓存操作
//添加之前先清理空闲的线程
void put(RealConnection connection) {
assert (Thread.holdsLock(this));
if (!cleanupRunning) {
cleanupRunning = true;
executor.execute(cleanupRunnable);
}
connections.add(connection);
}
//遍历connections列表当某个连接的次数小于限制的大小,并且request的地址和缓存列表中此连接完匹配时则直接复用缓存列表中connection作为request的连接
@Nullable RealConnection get(Address address, StreamAllocation streamAllocation, Route route) {
assert (Thread.holdsLock(this));
for (RealConnection connection : connections) {
if (connection.isEligible(address, route)) {
streamAllocation.acquire(connection, true);
return connection;
}
}
return null;
}
自动回收连接
private final Runnable cleanupRunnable = new Runnable() {
@Override public void run() {
while (true) {
//不断调用cleanup方法清理 并返回下次需要清理的间隔时间,然后调用wait方法进行等待以释放锁与时间片,当等待时间到了后,再次进行清理,并返回下次要清理的时间
long waitNanos = cleanup(System.nanoTime());
if (waitNanos == -1) return;
if (waitNanos > 0) {
long waitMillis = waitNanos / 1000000L;
waitNanos -= (waitMillis * 1000000L);
synchronized (ConnectionPool.this) {
try {
ConnectionPool.this.wait(waitMillis, (int) waitNanos);
} catch (InterruptedException ignored) {
}
}
}
}
}
};
//根据连接中的引用计数来计算空闲连接数和活跃连接数,然后标记出空闲的连接,如果空闲的连接超过5分钟,或者连接个数超过5个则从Deque中移除此连接,接下来根据空闲连接或者活跃连接来返回下次需要清理的时间数:如果空闲连接大于0,则返回此连接即将到期的时间,如果都是活跃连接并且大于0则返回默认的keepAlive时间5分钟。
//如果没有任何连接返回-1
//通过pruneAndGetAllocationCount 来判断连接是否空闲,如果返回值大于0 则是空闲连接,或者就是活跃连接
long cleanup(long now) {
int inUseConnectionCount = 0;
int idleConnectionCount = 0;
RealConnection longestIdleConnection = null;
long longestIdleDurationNs = Long.MIN_VALUE;
// Find either a connection to evict, or the time that the next eviction is due.
synchronized (this) {
for (Iterator<RealConnection> i = connections.iterator(); i.hasNext(); ) {
RealConnection connection = i.next();
// If the connection is in use, keep searching.
if (pruneAndGetAllocationCount(connection, now) > 0) {
inUseConnectionCount++;
continue;
}
idleConnectionCount++;
// If the connection is ready to be evicted, we're done.
long idleDurationNs = now - connection.idleAtNanos;
if (idleDurationNs > longestIdleDurationNs) {
longestIdleDurationNs = idleDurationNs;
longestIdleConnection = connection;
}
}
if (longestIdleDurationNs >= this.keepAliveDurationNs
|| idleConnectionCount > this.maxIdleConnections) {
// We've found a connection to evict. Remove it from the list, then close it below (outside
// of the synchronized block).
connections.remove(longestIdleConnection);
} else if (idleConnectionCount > 0) {
// A connection will be ready to evict soon.
return keepAliveDurationNs - longestIdleDurationNs;
} else if (inUseConnectionCount > 0) {
// All connections are in use. It'll be at least the keep alive duration 'til we run again.
return keepAliveDurationNs;
} else {
// No connections, idle or in use.
cleanupRunning = false;
return -1;
}
}
closeQuietly(longestIdleConnection.socket());
// Cleanup again immediately.
return 0;
}
//首先遍历传进来的RealConnection的StreamAllocation列表
//如果StreamAllocation被使用,则接着遍历下一个StreamAllocation 如果StreamAlloction未被使用则从列表中删除,如果列表为空则说明此连接没有引用了返回0,否则就返回非0表示此连接是活跃的
private int pruneAndGetAllocationCount(RealConnection connection, long now) {
List<Reference<StreamAllocation>> references = connection.allocations;
for (int i = 0; i < references.size(); ) {
Reference<StreamAllocation> reference = references.get(i);
if (reference.get() != null) {
i++;
continue;
}
// We've discovered a leaked allocation. This is an application bug.
StreamAllocation.StreamAllocationReference streamAllocRef =
(StreamAllocation.StreamAllocationReference) reference;
String message = "A connection to " + connection.route().address().url()
+ " was leaked. Did you forget to close a response body?";
Platform.get().logCloseableLeak(message, streamAllocRef.callStackTrace);
references.remove(i);
connection.noNewStreams = true;
// If this was the last allocation, the connection is eligible for immediate eviction.
if (references.isEmpty()) {
connection.idleAtNanos = now - keepAliveDurationNs;
return 0;
}
}
return references.size();
}
引用计数
StreamAllocation
在okhttp中使用了引用计数方式跟踪socket流的调用计数对象是StreamAllocation
它反复执行acquire,release操作这个两个操作在改变RealConnnection中的List<Reference> 大小
public void acquire(RealConnection connection, boolean reportedAcquired) {
assert (Thread.holdsLock(connectionPool));
if (this.connection != null) throw new IllegalStateException();
this.connection = connection;
this.reportedAcquired = reportedAcquired;
connection.allocations.add(new StreamAllocationReference(this, callStackTrace));
}
/** Remove this allocation from the connection's list of allocations. */
private void release(RealConnection connection) {
for (int i = 0, size = connection.allocations.size(); i < size; i++) {
Reference<StreamAllocation> reference = connection.allocations.get(i);
if (reference.get() == this) {
connection.allocations.remove(i);
return;
}
}
throw new IllegalStateException();
}
retrofit2
Retrofit基本用法
1,支持解析类型
Scalars,Jackson,Moshi,Protobuf,Wire,SimpleXML,Gson
2,注解分类
http请求方法注解:GET,POST,PUT,DELETE,HEAD,PATCH,OPTIONS
标记类注解3种:FormUrlEncoded,Multipart,Streaming
参数注解10种:Header,Headers,Body,Path,Field,FieldMap,Part,PartMap,Query,QueryMap
3,GET请求访问网络
public interface IpService{
@GET("getIpInfo.php?ip=xxxx")
Call<IpModel> getIpMsg();
//动态地址@Path
@GET("{path}/getIpInfo.php?ip=xxxxx")
Call<IpModel> getIpMsg(@Path("path")String path);
//动态指定查询条件@Query
@GET("getIpInfo.php")
Call<IpModel> getIpMsg(@Query("ip")String ip);
//动态指定查询条件数组
@GET("getIpInfo.php")
Call<IpModel> getIpMsg(@QueryMap Map<String,String> options);
}
String BaseUrl = "http://ip.taobao.com/service/";
Retrofit retofit=new Retrofit.Builder()
.baseUrl(BaseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
IpService ipService = retrofit.create(IpService.class)
Call<IpModel> call = ipService.getIpMsg();
4 POST 请求访问网络
@Field:传输类型为键值对
public interface IpServiceForPost{
@FormUrlEncoded //表示这个是一个表单请求
@POST("getIpInfo.php")
Call<IpModel> getIpMsg(@Field("ip")String first);
// 将json 字符串发送到服务端
// @Body 表识 将对象转换为字符串
@POST("getIpInfo.php")
Call<IpModel> getIpMsg(@Body Ip ip);
//单个文件上传
@Multipart //表示允许多个@Part
@POST("user/photo")
// MultipartBody.Part 准备上传到图片文件
//RequestBody 传递简单的键值对
Call<User> updateUser(@Part MultipartBody.Part photo,@Part("description")RequestBody description);
//多文件上传
@Multipart
@POST("user/photo")
Call<User> updateUser(@PartMap Map<String,RequestBody> photos,@Part("description")RequestBody description);
}
File file = new File(Environment.getExternalStorageDirectory()+"xxx.png");
RequestBody body = RequestBody.create(MediaType.parse("image/png"),file );
MultipartBody.Part part=MultipartBody.Part.createFormData("photos", "xxx.png",body);
IpServiceForPost.updateUser(part,RequestBody.create(null,"xxxxxxx"));
5,消息报头Header
interface SomeService{
@GET("some/endpoint")
@Headers("Accept-Encoding:application/json")//添加消息报头
//如果添加多个消息报头可以使用{}
// @Headers({"Accept-Encoding:application/json","User-Agent:MoonRetrofit"})
Call<ResponseBody> getCarType();
//动态方式添加报头
@GET("some/endpoint")
Call<ResponseBody> getCarType(@Header("Location") String location);
}
源码解析
1,Retrofit 的创建过程
当使用retrofit请求网络时,首先要写请求接口,接着我们创建retrofit
retrofit通过建造者模式构建出来。
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("")
.addConverterFactory(GsonConverterFactory.create())
.build();
public Builder() {
this(Platform.get());
}
//根据不同的平台来提供不同的线程池
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("java.util.Optional");
return new Java8();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
//build()方法
public Retrofit build() {
//baseUrl 必须有
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//我们调用.callFactory(null) 传递进来的
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
//将回调传递到UI线程
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
//用于存储对call进行转化的对象
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
//添加默认的 ExecutorCallAdapterFactory 执行器
callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
//用于存储转化数据对象
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories =
new ArrayList<>(1 + this.converterFactories.size());
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
}
2,Call 的创建过程
@SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
//返回一个动态代理对象
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
//proxy 代理对象
//method 调用方法
// args 方法参数
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
// loadServiceMethod 调用接口方法
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
}
});
}
ServiceMethod<?, ?> loadServiceMethod(Method method) {
//serviceMethodCache 查询传入的方法是否有缓存 如果有就用缓存 如果没有就创建一个并加入serviceMethodCache缓存中
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
ServiceMethod 的构建
public ServiceMethod build() {
//构建接口返回的数据类型
callAdapter = createCallAdapter();
//得到返回数据的真实类型
responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError("'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
//遍历converterFactories列表中存储的Converter.Factories 并返回一个合适的Converter用来转换对象
responseConverter = createResponseConverter();
for (Annotation annotation : methodAnnotations) {
//遍历 parseMethodAnnotation 方法来对请求方式(比如@GET,@POST)和请求地址进行解析
parseMethodAnnotation(annotation);
}
if (httpMethod == null) {
throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
if (!hasBody) {
if (isMultipart) {
throw methodError(
"Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
}
if (isFormEncoded) {
throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
+ "request body (e.g., @POST).");
}
}
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
if (Utils.hasUnresolvableType(parameterType)) {
throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
parameterType);
}
//对方法中的参数注解进行解析(比如@Query,@Part)
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
if (parameterAnnotations == null) {
throw parameterError(p, "No Retrofit annotation found.");
}
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
if (relativeUrl == null && !gotUrl) {
throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
}
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
throw methodError("Non-body HTTP method cannot contain @Body.");
}
if (isFormEncoded && !gotField) {
throw methodError("Form-encoded method must contain at least one @Field.");
}
if (isMultipart && !gotPart) {
throw methodError("Multipart method must contain at least one @Part.");
}
return new ServiceMethod<>(this);
}
创建CallAdapter
private CallAdapter<T, R> createCallAdapter() {
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError("Service methods cannot return void.");
}
Annotation[] annotations = method.getAnnotations();
try {
//noinspection unchecked
return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}
最终调用okhttp请求网络
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
//就是OkhttpCall
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
@Override public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
OkhttpCall 中enqueue
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
okhttp3.Call call;
Throwable failure;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) {
try {
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
//解析请求结果
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
解析请求结果封装成Response对象
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
// Remove the body's source (the only stateful object) so we can pass the response along.
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
int code = rawResponse.code();
if (code < 200 || code >= 300) {
try {
// Buffer the entire body to avoid future I/O.
ResponseBody bufferedBody = Utils.buffer(rawBody);
return Response.error(bufferedBody, rawResponse);
} finally {
rawBody.close();
}
}
if (code == 204 || code == 205) {
rawBody.close();
return Response.success(null, rawResponse);
}
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
//根据我们传入的转换工程进行数据转换 比如我们传入 GsonConverFactory
T body = serviceMethod.toResponse(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
// If the underlying source threw an exception, propagate that rather than indicating it was
// a runtime exception.
catchingBody.throwIfCaught();
throw e;
}
}
GsonFactory 转换过程
@Override public T convert(ResponseBody value) throws IOException {
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
return adapter.read(jsonReader);
} finally {
value.close();
}
}