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
)
;
}
}
}
}