您的位置:首页 > 其它

Retrofit1.9源码解析(二)

2015-12-17 21:40 661 查看
Retrofit已经出到2.0了,但项目里的是1.9所以就来分析下它的源码。
要讲Retrofit,就必须要知道动态代理模式建造者模式。一开始使用的时,须要设置参数,如果没有设置,就用默认的。
restAdapter
=
new
RestAdapter.Builder()

.setEndpoint(""
)

.setLogLevel(RestAdapter.LogLevel.FULL)

.setClient(new
OkClient(getClient()))

.setLog(new
RestAdapter.Log() {

@Override

public void
log(String msg) {

Log.i(TAG,
msg);

}

})
.build();
private void
ensureSaneDefaults() {

if
(converter
==
null) {

converter
= Platform.get().defaultConverter();

}

if
(clientProvider
==
null) {

clientProvider
= Platform.get().defaultClient();

}

if
(httpExecutor
==
null) {

httpExecutor
= Platform.get().defaultHttpExecutor();

}

if
(callbackExecutor
==
null) {

callbackExecutor
= Platform.get().defaultCallbackExecutor();

}

if
(errorHandler
==
null) {

errorHandler
= ErrorHandler.DEFAULT;

}

if
(log
==
null) {

log
= Platform.get().defaultLog();

}

if
(requestInterceptor
==
null) {

requestInterceptor
= RequestInterceptor.NONE;

}
}
设置好参数之后,就只需要通过以下代码就能得到clazz接口的代理,这里必须是接口。以前对代理模式以为只有在有实现者时才能使用,而Retrofit告诉我不只如此,虽然没有实现类,但通过代理已经实现了每个方法,具体做什么,是由框架自己决定的。
restAdapter
.create(clazz);
从下面代码可以看出,重点是RestHandler.
public
<T>
T
create(Class<
T> service) {

Utils.validateServiceClass(service)
;

return (T)
Proxy. newProxyInstance(service.getClassLoader()
, new
Class<?>[] { service }
,

new RestHandler(getMethodInfoCache(service)))
;
}
首先是获取这个接口的缓存,如果已经解析过,就直接get,否则就新建个map,有个重点类RestMethodInfo。在RestMethodInfo里会判断两种情况,一种是返回值,一种是Callback回调,在这里只能使用一种。
/** Loads {@link
#responseObjectType}. Returns {@code
true} if method is synchronous. */

private
ResponseType
parseResponseType
() {

// Synchronous methods have a non-void return type.

// Observable methods have a return type of Observable.

Type returnType =
method.getGenericReturnType();

// Asynchronous methods should have a Callback type as the last argument.

Type lastArgType =
null;

Class<?>
lastArgClass
= null;

Type[] parameterTypes =
method.getGenericParameterTypes();

if (parameterTypes.
length
>
0
) {

Type typeToCheck = parameterTypes[parameterTypes.length
-
1]
;

lastArgType = typeToCheck
;

if (typeToCheck
instanceof
ParameterizedType) {

typeToCheck = ((ParameterizedType) typeToCheck).getRawType();

}

if
(typeToCheck
instanceof
Class) {

lastArgClass
= (Class<?>) typeToCheck
;

}

}

boolean
hasReturnType = returnType !=
void
.class;

boolean hasCallback =
lastArgClass
!= null
&& Callback.class.isAssignableFrom(lastArgClass
);

// Check for invalid configurations.

if
(hasReturnType && hasCallback) {

throw
methodError("Must have return type or Callback as last
argument, not both.")
;

}

if
(!hasReturnType && !hasCallback) {

throw
methodError("Must have either a return type or Callback
as last argument.");

}

if
(hasReturnType) {

if
(Platform.HAS_RX_JAVA)
{

Class rawReturnType = Types.getRawType
(returnType);

if (RxSupport.
isObservable(rawReturnType)) {

returnType = RxSupport.getObservableType
(returnType,
rawReturnType);

responseObjectType
=
getParameterUpperBound((ParameterizedType) returnType)
;

return ResponseType.
OBSERVABLE;

}

}

responseObjectType
= returnType;

return ResponseType.
OBJECT;

}

lastArgType = Types.getSupertype(lastArgType
,
Types.getRawType(lastArgType),
Callback.
class);

if (lastArgType
instanceof
ParameterizedType) {

responseObjectType
=
getParameterUpperBound((ParameterizedType) lastArgType)
;

return ResponseType.
VOID;

}

throw
methodError("Last parameter must be of type Callback<X>
or Callback<? super X>.")
;
}
暂时只关注CallBack方式,的只需要CallBackRunnable那段代码就行。

private class
RestHandler
implements
InvocationHandler {

private final
Map<Method,
RestMethodInfo>
methodDetailsCache;

RestHandler(Map<Method
,
RestMethodInfo> methodDetailsCache) {

this
.methodDetailsCache
= methodDetailsCache
;

}

@SuppressWarnings
("unchecked")
//

@Override
public
Object
invoke(Object proxy,
Method method, final
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)
;

}

// Load or create the details cache for the current method.

final
RestMethodInfo methodInfo =
getMethodInfo(
methodDetailsCache,
method)
;

if (methodInfo.
isSynchronous) {

try
{

return
invokeRequest(requestInterceptor,
methodInfo,
args)
;

}
catch
(RetrofitError error) {

Throwable newError =
errorHandler
.handleError(error);

if (newError ==
null) {

throw new
IllegalStateException("Error handler returned null
for wrapped exception.",

error)
;

}

throw
newError;

}

}

if
(httpExecutor
==
null
||
callbackExecutor
==
null) {

throw new
IllegalStateException("Asynchronous invocation requires
calling setExecutors.")
;

}

if
(methodInfo.isObservable)
{

if
(rxSupport
==
null) {

if
(Platform.HAS_RX_JAVA)
{

rxSupport
=
new
RxSupport(
httpExecutor,
errorHandler
,
requestInterceptor
);

}
else
{

throw new
IllegalStateException("Observable method found but
no RxJava on classpath.")
;

}

}

return
rxSupport.createRequestObservable(new
RxSupport.Invoker() {

@Override
public
ResponseWrapper
invoke
(RequestInterceptor requestInterceptor) {

return
(ResponseWrapper) invokeRequest(requestInterceptor
,
methodInfo,
args
);

}

});

}

// Apply the interceptor synchronously, recording the interception so we can replay it later.

// This way we still defer argument serialization to the background thread.

final
RequestInterceptorTape interceptorTape =
new
RequestInterceptorTape()
;

requestInterceptor
.intercept(interceptorTape);

Callback<?> callback = (Callback<?>) args[args.
length
-
1
];

httpExecutor
.execute(new
CallbackRunnable(callback
,
callbackExecutor,
errorHandler
) {

@Override
public
ResponseWrapper
obtainResponse
() {

return
(ResponseWrapper) invokeRequest(
interceptorTape,
methodInfo,
args
);

}

});

return null; // Asynchronous methods should have return type of void.

}
下面这个是CallBackRunnable的Run代码,注意到一开始就调用了obtainResponse(),也是在这里发送请求的,又交给了RestAdapter类执行。
@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)
;

}

});

}
}
在下面代码里,一开始就去解析这个方法的Annotation跟参数Annotation,得到这个url的请求方式,路径,头部等信息。再经过RequestBuider跟ServerUrl组装起来,最后交给Client请求,在这里目前是OKClient.这个是在PlatForm里得到的。最后就把返回结果转化后回调CallBack,这个是通过Retrofit的线程池来的:

callbackExecutor
.execute(new
Runnable() {

@Override
public void
run
() {

callback
.success((T)
wrapper.responseBody
,
wrapper.
response);

}
});

/**

* Execute an HTTP request.

*

* @return
HTTP response object of specified {@code
type} or {@code
null}.

* @throws
RetrofitError if any error occurs during the HTTP request.

*/

private
Object
invokeRequest(RequestInterceptor requestInterceptor
,
RestMethodInfo methodInfo
,

Object[] args) {

String url = null;

try {

methodInfo.init();
// Ensure all relevant method information has been loaded.

String serverUrl =
server.getUrl();

RequestBuilder requestBuilder =
new
RequestBuilder(serverUrl,
methodInfo,
converter
);

requestBuilder.setArguments(args)
;

requestInterceptor.intercept(requestBuilder)
;

Request request = requestBuilder.build()
;

url = request.getUrl()
;

if (!methodInfo.
isSynchronous) {

// If we are executing asynchronously then update the current thread with a useful name.

int
substrEnd = url.indexOf("?",
serverUrl.length());

if (substrEnd == -
1) {

substrEnd = url.length();

}

Thread.currentThread
().setName(THREAD_PREFIX

+ url.substring(serverUrl.length()
,
substrEnd));

}

if
(logLevel.log())
{

// Log the request data.

request = logAndReplaceRequest(
"HTTP",
request
,
args);

}

Object profilerObject =
null;

if (
profiler
!=
null
) {

profilerObject =
profiler
.beforeCall();

}

long
start = System.nanoTime();

Response response =
clientProvider.get().execute(request);

long elapsedTime = TimeUnit.NANOSECONDS
.toMillis(System.nanoTime() - start);

int statusCode = response.getStatus()
;

if (
profiler
!=
null
) {

RequestInformation requestInfo =
getRequestInfo(serverUrl,
methodInfo,
request)
;

//noinspection unchecked

profiler
.afterCall(requestInfo,
elapsedTime
,
statusCode,
profilerObject);

}

if
(logLevel.log())
{

// Log the response data.

response = logAndReplaceResponse(url
,
response,
elapsedTime);

}

Type type = methodInfo.responseObjectType
;

if (statusCode >=
200
&& statusCode <
300
) {
// 2XX == successful request

// Caller requested the raw Response object directly.

if
(type.equals(Response.class))
{

if
(!methodInfo.isStreaming)
{

// Read the entire stream and replace with one backed by a byte[].

response = Utils.
readBodyToBytesIfNecessary(response)
;

}

if
(methodInfo.isSynchronous)
{

return
response;

}

return new
ResponseWrapper(response,
response)
;

}

TypedInput body = response.getBody();

if (body ==
null) {

if
(methodInfo.isSynchronous)
{

return null;

}

return new
ResponseWrapper(response, null)
;

}

ExceptionCatchingTypedInput wrapped =
new
ExceptionCatchingTypedInput(body)
;

try {

Object convert =
converter
.fromBody(wrapped,
type)
;

logResponseBody(body
,
convert);

if (methodInfo.
isSynchronous) {

return
convert;

}

return new
ResponseWrapper(response,
convert)
;

}
catch
(ConversionException e) {

// If the underlying input stream threw an exception, propagate that rather than

// indicating that it was a conversion exception.

if
(wrapped.threwException()) {

throw
wrapped.getThrownException();

}

// The response body was partially read by the converter. Replace it with null.

response = Utils.
replaceResponseBody(response
, null);

throw RetrofitError.
conversionError(url
,
response,
converter,
type
,
e);

}

}

response = Utils.readBodyToBytesIfNecessary
(response);

throw RetrofitError.
httpError(url
,
response,
converter,
type)
;

}
catch
(RetrofitError e) {

throw
e;
// Pass through our own errors.

}
catch
(IOException e) {

if
(logLevel.log())
{

logException(e,
url);

}

throw
RetrofitError.networkError(url,
e);

}
catch
(Throwable t) {

if
(logLevel.log())
{

logException(t,
url);

}

throw
RetrofitError.unexpectedError(url,
t)
;

}
finally
{

if
(!methodInfo.isSynchronous)
{

Thread.currentThread
().setName(IDLE_THREAD_NAME)
;

}

}

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: