前面基本的原理和流程已经弄清了.再研究下某些实现.
CallbackRunnable(异步模式时在子线程执行的部分)
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.因为方法的返回值只能是一个.所以用它包装了下.
final class ResponseWrapper {
final Response response;
final Object responseBody;
ResponseWrapper(Response response, Object responseBody) {
this.response = response;
this.responseBody = responseBody;
}
}
Retrofit的Client是真正进行网络访问的逻辑.来看下具体的实现.
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
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个方法的返回值是一样的.
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返回的类型就应该和接口方法的返回值类型一样.