前面基本的原理和流程已经弄清了.再研究下某些实现.
CallbackRunnable(异步模式时在子线程执行的部分)
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
|
abstract
class
CallbackRunnable<T>
implements
Runnable {
private
final
Callback<T> callback;
private
final
Executor callbackExecutor;
private
final
ErrorHandler errorHandler;
CallbackRunnable(Callback<T> callback, Executor callbackExecutor, ErrorHandler errorHandler) {
this
.callback = callback;
this
.callbackExecutor = callbackExecutor;
this
.errorHandler = errorHandler;
}
@SuppressWarnings
(
"unchecked"
)
@Override
public
final
void
run() {
//在异步线程中实际执行的方法.
try
{
final
ResponseWrapper wrapper = obtainResponse();
callbackExecutor.execute(
new
Runnable() {
@Override
public
void
run() {
callback.success((T) wrapper.responseBody, wrapper.response);
//在主线程执行.
}
});
}
catch
(RetrofitError e) {
Throwable cause = errorHandler.handleError(e);
//这里的异常捕捉到了以后没有再次抛出,内部处理了.
final
RetrofitError handled = cause == e ? e : unexpectedError(e.getUrl(), cause);
callbackExecutor.execute(
new
Runnable() {
@Override
public
void
run() {
callback.failure(handled);
//在主线程执行.
}
});
}
}
public
abstract
ResponseWrapper obtainResponse();
//交给子类实现--->其实就是执行的前面的invokeRequest().
}
|
ResponseWrapper封装了response和responseBody.因为方法的返回值只能是一个.所以用它包装了下.
1
2
3
4
5
6
7
8
9
|
final
class
ResponseWrapper {
final
Response response;
final
Object responseBody;
ResponseWrapper(Response response, Object responseBody) {
this
.response = response;
this
.responseBody = responseBody;
}
}
|
Retrofit的Client是真正进行网络访问的逻辑.来看下具体的实现.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public
interface
Client {
/**
* Synchronously execute an HTTP represented by {@code request} and encapsulate all response data
* into a {@link Response} instance.
* <p>
* Note: If the request has a body, its length and mime type will have already been added to the
* header list as {@code Content-Length} and {@code Content-Type}, respectively. Do NOT alter
* these values as they might have been set as a result of an application-level configuration.
*/
Response execute(Request request)
throws
IOException;
//抽象方法,就是给定一个Request,执行完,返回一个Response.
/**
* Deferred means of obtaining a {@link Client}. For asynchronous requests this will always be
* called on a background thread.
*/
interface
Provider {
/** Obtain an HTTP client. Called once for each request. */
Client get();
}
}
|
OkClient
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
|
public
class
OkClient
implements
Client {
private
static
OkHttpClient generateDefaultOkHttp() {
OkHttpClient client =
new
OkHttpClient();
client.setConnectTimeout(Defaults.CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
client.setReadTimeout(Defaults.READ_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
return
client;
}
private
final
OkHttpClient client;
public
OkClient() {
this
(generateDefaultOkHttp());
}
public
OkClient(OkHttpClient client) {
if
(client ==
null
)
throw
new
NullPointerException(
"client == null"
);
this
.client = client;
}
@Override
public
Response execute(Request request)
throws
IOException {
return
parseResponse(client.newCall(createRequest(request)).execute());
//client.newCall().execute() 真正利用okHttp进行网络访问的地方.可以看到是采用的Okhttp的同步的方式.
}
static
com.squareup.okhttp.Request createRequest(Request request) {
//把retrofit的Request中url,header等信息提取出来, 封装进okhttp的Request中.
com.squareup.okhttp.Request.Builder builder =
new
com.squareup.okhttp.Request.Builder()
.url(request.getUrl())
.method(request.getMethod(), createRequestBody(request.getBody()));
List<Header> headers = request.getHeaders();
for
(
int
i =
0
, size = headers.size(); i < size; i++) {
Header header = headers.get(i);
String value = header.getValue();
if
(value ==
null
) value =
""
;
builder.addHeader(header.getName(), value);
}
return
builder.build();
}
static
Response parseResponse(com.squareup.okhttp.Response response) {
return
new
Response(response.request().urlString(), response.code(), response.message(),
createHeaders(response.headers()), createResponseBody(response.body()));
}
private
static
RequestBody createRequestBody(
final
TypedOutput body) {
if
(body ==
null
) {
return
null
;
}
final
MediaType mediaType = MediaType.parse(body.mimeType());
//解析Response的类型.
return
new
RequestBody() {
@Override
public
MediaType contentType() {
return
mediaType;
}
@Override
public
void
writeTo(BufferedSink sink)
throws
IOException {
body.writeTo(sink.outputStream());
}
@Override
public
long
contentLength() {
return
body.length();
}
};
}
private
static
TypedInput createResponseBody(
final
ResponseBody body) {
if
(body.contentLength() ==
0
) {
return
null
;
}
return
new
TypedInput() {
@Override
public
String mimeType() {
MediaType mediaType = body.contentType();
return
mediaType ==
null
?
null
: mediaType.toString();
}
@Override
public
long
length() {
return
body.contentLength();
}
@Override
public
InputStream in()
throws
IOException {
return
body.byteStream();
}
};
}
private
static
List<Header> createHeaders(Headers headers) {
int
size = headers.size();
List<Header> headerList =
new
ArrayList<Header>(size);
for
(
int
i =
0
; i < size; i++) {
headerList.add(
new
Header(headers.name(i), headers.value(i)));
}
return
headerList;
}
}
|
retrofit的大体流程.
用户自定义配置项的设置(如client,converter,拦截器等)--->解析接口的方法(如果曾经解析过就从缓存中获取),确定http访问的url,header,method等,确定是异步还是同步的方式------>使用具体的Client进行网络访问,并将数据封装到Response---->执行Converter的逻辑(有可能不用执行),把Response数据转换为一个具体对象.--->根据同步或者异步的方式,执行方法或者callBack的逻辑.
retrofit框架的需要注意的几个小点.
1.为什么同步方式不像正常的方式一样要求用户try_catch来提醒用户捕捉异常?
通过上面的逻辑可以看到,真正进行网络访问,converter转换的逻辑都在invokeHandler.invoke()方法执行的时候执行. 而这个方法的调用是在 用户自定义接口调用接口方法的时候执行的.(不明白的可以看下动态代理的原理).而用户自定义的接口方法是没有抛出异常的.在java中,如果父类方法没有抛出异常,子类方法也不能显示的抛出异常.(子类方法只能抛出父类方法抛出异常或其子类).所以Retrofit就不能抛出各种异常(如IO异常). 并且要抓住异常后转换为RuntimeException抛出.(动态代理生成的接口的实现类其实内部也采用了同样的方法.)
异常抓住后不能直接内部处理,应该提醒用户代码执行的时候出了问题,所以必须抓住异常后再次抛出.而对于CallBack的方式,因为有failure()方法提示用户代码逻辑出了问题,所以就不用re-throw异常了.
2.关于 InvocationHandler的invoke()方法, 这个方法有个返回值. 那这个返回值返回的是什么呢?
首先明确Method.invoke(Object receiver,Object.. args)是和 receiver.method(args)等价的,2个方法的返回值是一样的.
1
2
|
public
Object invoke(Object receiver, Object... args) 这里的Object是方法执行的的返回值.
---> Returns the result of dynamically invoking
this
method. Equivalent to {
@code
receiver.methodName(arg1, arg2, ... , argN)}.
|
动态代理生成了接口A的代理类B,B的同名方法内部其实调用的是invocationHandler的 invoke()方法.返回的也是invoke方法的返回值. 所以invoke返回的类型就应该和接口方法的返回值类型一样.