Retrofit turns your HTTP API into a Java interface.(将HTTP API转换为Java接口。)
public interface GitHubService { @GET("users/{user}/repos") Call > listRepos(@Path("user") String user);}复制代码
The Retrofit class generates an implementation of the GitHubService interface.(Retrofit类生成GitHubService接口的实现。)
Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/") .build();GitHubService service = retrofit.create(GitHubService.class);复制代码
Each Call from the created GitHubService can make a synchronous or asynchronous HTTP request to the remote webserver. (创建的GitHubService的每个调用都可以向远程web服务器发出同步或异步的HTTP请求。)
Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/") .build();复制代码
我们可以看到retrofit的构建使用了builder模式。
1. 看一下Retrofit.Builder类:
/** * Build a new {@link Retrofit}. *
* Calling {@link #baseUrl} is required before calling {@link #build()}. All other methods * are optional. */ public static final class Builder { private final Platform platform; private @Nullable okhttp3.Call.Factory callFactory; private HttpUrl baseUrl; private final List
converterFactories = new ArrayList<>(); private final List adapterFactories = new ArrayList<>(); private @Nullable Executor callbackExecutor; private boolean validateEagerly; ... }复制代码
/** * Create the {@link Retrofit} instance using the configured values. *
* Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link * OkHttpClient} will be created and used. */ //通过配置参数创建一个Retrofit的实例,如果没有配置HttpClient也没有配置CallFactory将采用默认的OkHttpClient public Retrofit build() { if (baseUrl == null) { // baseUrl不能为空 throw new IllegalStateException("Base URL required."); } //配置HttpClient,可以看出retrofit默认采用OkHttpClient okhttp3.Call.Factory callFactory = this.callFactory; if (callFactory == null) { callFactory = new OkHttpClient(); } //指定callback回调方法的执行器,这里的platform是Android平台,可以看出默认下面的Android--Platform的MainThreadExecutor Executor callbackExecutor = this.callbackExecutor; if (callbackExecutor == null) { callbackExecutor = platform.defaultCallbackExecutor(); } // Make a defensive copy of the adapters and add the default Call adapter. //将我们自定义的adapterFactory添加到集合中 List
adapterFactories = new ArrayList<>(this.adapterFactories); adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor)); // Make a defensive copy of the converters. //将我们自定义的convertFactory添加到集合中 List converterFactories = new ArrayList<>(this.converterFactories); // 返回Retrofit return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories, callbackExecutor, validateEagerly); }复制代码
Android--Platform
static class Android extends Platform { @Override public Executor defaultCallbackExecutor() { return new MainThreadExecutor(); } @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) { if (callbackExecutor == null) throw new AssertionError(); return new ExecutorCallAdapterFactory(callbackExecutor); } static class MainThreadExecutor implements Executor { private final Handler handler = new Handler(Looper.getMainLooper()); @Override public void execute(Runnable r) { handler.post(r); } } }复制代码
GitHubService service = retrofit.create(GitHubService.class);复制代码
来生成我们service接口的实现类。我们来看create()方法。
3. retrofit.create()
public T create(final Class 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(); @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); } ServiceMethod
private ParameterHandler parseParameterAnnotation( int p, Type type, Annotation[] annotations, Annotation annotation) { if (annotation instanceof Url) { if (gotUrl) { throw parameterError(p, "Multiple @Url method annotations found."); } if (gotPath) { throw parameterError(p, "@Path parameters may not be used with @Url."); } if (gotQuery) { throw parameterError(p, "A @Url parameter must not come after a @Query"); } if (relativeUrl != null) { throw parameterError(p, "@Url cannot be used with @%s URL", httpMethod); } gotUrl = true; if (type == HttpUrl.class || type == String.class || type == URI.class || (type instanceof Class && "android.net.Uri".equals(((Class ) type).getName()))) { return new ParameterHandler.RelativeUrl(); } else { throw parameterError(p, "@Url must be okhttp3.HttpUrl, String, java.net.URI, or android.net.Uri type."); } } else if (annotation instanceof Path) { if (gotQuery) { throw parameterError(p, "A @Path parameter must not come after a @Query."); } if (gotUrl) { throw parameterError(p, "@Path parameters may not be used with @Url."); } if (relativeUrl == null) { throw parameterError(p, "@Path can only be used with relative url on @%s", httpMethod); } gotPath = true; Path path = (Path) annotation; String name = path.value(); validatePathName(p, name); Converter converter = retrofit.stringConverter(type, annotations); return new ParameterHandler.Path<>(name, converter, path.encoded()); } else if (annotation instanceof Query) { Query query = (Query) annotation; String name = query.value(); boolean encoded = query.encoded(); Class rawParameterType = Utils.getRawType(type); gotQuery = true; if (Iterable.class.isAssignableFrom(rawParameterType)) { if (!(type instanceof ParameterizedType)) { throw parameterError(p, rawParameterType.getSimpleName() + " must include generic type (e.g., " + rawParameterType.getSimpleName() + " )"); } ParameterizedType parameterizedType = (ParameterizedType) type; Type iterableType = Utils.getParameterUpperBound(0, parameterizedType); Converter converter = retrofit.stringConverter(iterableType, annotations); return new ParameterHandler.Query<>(name, converter, encoded).iterable(); } else if (rawParameterType.isArray()) { Class arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType()); Converter converter = retrofit.stringConverter(arrayComponentType, annotations); return new ParameterHandler.Query<>(name, converter, encoded).array(); } else { Converter converter = retrofit.stringConverter(type, annotations); return new ParameterHandler.Query<>(name, converter, encoded); } } else if (annotation instanceof QueryName) { QueryName query = (QueryName) annotation; boolean encoded = query.encoded(); Class rawParameterType = Utils.getRawType(type); gotQuery = true; if (Iterable.class.isAssignableFrom(rawParameterType)) { if (!(type instanceof ParameterizedType)) { throw parameterError(p, rawParameterType.getSimpleName() + " must include generic type (e.g., " + rawParameterType.getSimpleName() + " )"); } ParameterizedType parameterizedType = (ParameterizedType) type; Type iterableType = Utils.getParameterUpperBound(0, parameterizedType); Converter converter = retrofit.stringConverter(iterableType, annotations); return new ParameterHandler.QueryName<>(converter, encoded).iterable(); } else if (rawParameterType.isArray()) { Class arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType()); Converter converter = retrofit.stringConverter(arrayComponentType, annotations); return new ParameterHandler.QueryName<>(converter, encoded).array(); } else { Converter converter = retrofit.stringConverter(type, annotations); return new ParameterHandler.QueryName<>(converter, encoded); } } else if (annotation instanceof QueryMap) { Class rawParameterType = Utils.getRawType(type); if (!Map.class.isAssignableFrom(rawParameterType)) { throw parameterError(p, "@QueryMap parameter type must be Map."); } Type mapType = Utils.getSupertype(type, rawParameterType, Map.class); if (!(mapType instanceof ParameterizedType)) { throw parameterError(p, "Map must include generic types (e.g., Map )"); } ParameterizedType parameterizedType = (ParameterizedType) mapType; Type keyType = Utils.getParameterUpperBound(0, parameterizedType); if (String.class != keyType) { throw parameterError(p, "@QueryMap keys must be of type String: " + keyType); } Type valueType = Utils.getParameterUpperBound(1, parameterizedType); Converter valueConverter = retrofit.stringConverter(valueType, annotations); return new ParameterHandler.QueryMap<>(valueConverter, ((QueryMap) annotation).encoded()); } else if (annotation instanceof Header) { Header header = (Header) annotation; String name = header.value(); Class rawParameterType = Utils.getRawType(type); if (Iterable.class.isAssignableFrom(rawParameterType)) { if (!(type instanceof ParameterizedType)) { throw parameterError(p, rawParameterType.getSimpleName() + " must include generic type (e.g., " + rawParameterType.getSimpleName() + " )"); } ParameterizedType parameterizedType = (ParameterizedType) type; Type iterableType = Utils.getParameterUpperBound(0, parameterizedType); Converter converter = retrofit.stringConverter(iterableType, annotations); return new ParameterHandler.Header<>(name, converter).iterable(); } else if (rawParameterType.isArray()) { Class arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType()); Converter converter = retrofit.stringConverter(arrayComponentType, annotations); return new ParameterHandler.Header<>(name, converter).array(); } else { Converter converter = retrofit.stringConverter(type, annotations); return new ParameterHandler.Header<>(name, converter); } } else if (annotation instanceof HeaderMap) { Class rawParameterType = Utils.getRawType(type); if (!Map.class.isAssignableFrom(rawParameterType)) { throw parameterError(p, "@HeaderMap parameter type must be Map."); } Type mapType = Utils.getSupertype(type, rawParameterType, Map.class); if (!(mapType instanceof ParameterizedType)) { throw parameterError(p, "Map must include generic types (e.g., Map )"); } ParameterizedType parameterizedType = (ParameterizedType) mapType; Type keyType = Utils.getParameterUpperBound(0, parameterizedType); if (String.class != keyType) { throw parameterError(p, "@HeaderMap keys must be of type String: " + keyType); } Type valueType = Utils.getParameterUpperBound(1, parameterizedType); Converter valueConverter = retrofit.stringConverter(valueType, annotations); return new ParameterHandler.HeaderMap<>(valueConverter); } else if (annotation instanceof Field) { if (!isFormEncoded) { throw parameterError(p, "@Field parameters can only be used with form encoding."); } Field field = (Field) annotation; String name = field.value(); boolean encoded = field.encoded(); gotField = true; Class rawParameterType = Utils.getRawType(type); if (Iterable.class.isAssignableFrom(rawParameterType)) { if (!(type instanceof ParameterizedType)) { throw parameterError(p, rawParameterType.getSimpleName() + " must include generic type (e.g., " + rawParameterType.getSimpleName() + " )"); } ParameterizedType parameterizedType = (ParameterizedType) type; Type iterableType = Utils.getParameterUpperBound(0, parameterizedType); Converter converter = retrofit.stringConverter(iterableType, annotations); return new ParameterHandler.Field<>(name, converter, encoded).iterable(); } else if (rawParameterType.isArray()) { Class arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType()); Converter converter = retrofit.stringConverter(arrayComponentType, annotations); return new ParameterHandler.Field<>(name, converter, encoded).array(); } else { Converter converter = retrofit.stringConverter(type, annotations); return new ParameterHandler.Field<>(name, converter, encoded); } } else if (annotation instanceof FieldMap) { if (!isFormEncoded) { throw parameterError(p, "@FieldMap parameters can only be used with form encoding."); } Class rawParameterType = Utils.getRawType(type); if (!Map.class.isAssignableFrom(rawParameterType)) { throw parameterError(p, "@FieldMap parameter type must be Map."); } Type mapType = Utils.getSupertype(type, rawParameterType, Map.class); if (!(mapType instanceof ParameterizedType)) { throw parameterError(p, "Map must include generic types (e.g., Map )"); } ParameterizedType parameterizedType = (ParameterizedType) mapType; Type keyType = Utils.getParameterUpperBound(0, parameterizedType); if (String.class != keyType) { throw parameterError(p, "@FieldMap keys must be of type String: " + keyType); } Type valueType = Utils.getParameterUpperBound(1, parameterizedType); Converter valueConverter = retrofit.stringConverter(valueType, annotations); gotField = true; return new ParameterHandler.FieldMap<>(valueConverter, ((FieldMap) annotation).encoded()); } else if (annotation instanceof Part) { if (!isMultipart) { throw parameterError(p, "@Part parameters can only be used with multipart encoding."); } Part part = (Part) annotation; gotPart = true; String partName = part.value(); Class rawParameterType = Utils.getRawType(type); if (partName.isEmpty()) { if (Iterable.class.isAssignableFrom(rawParameterType)) { if (!(type instanceof ParameterizedType)) { throw parameterError(p, rawParameterType.getSimpleName() + " must include generic type (e.g., " + rawParameterType.getSimpleName() + " )"); } ParameterizedType parameterizedType = (ParameterizedType) type; Type iterableType = Utils.getParameterUpperBound(0, parameterizedType); if (!MultipartBody.Part.class.isAssignableFrom(Utils.getRawType(iterableType))) { throw parameterError(p, "@Part annotation must supply a name or use MultipartBody.Part parameter type."); } return ParameterHandler.RawPart.INSTANCE.iterable(); } else if (rawParameterType.isArray()) { Class arrayComponentType = rawParameterType.getComponentType(); if (!MultipartBody.Part.class.isAssignableFrom(arrayComponentType)) { throw parameterError(p, "@Part annotation must supply a name or use MultipartBody.Part parameter type."); } return ParameterHandler.RawPart.INSTANCE.array(); } else if (MultipartBody.Part.class.isAssignableFrom(rawParameterType)) { return ParameterHandler.RawPart.INSTANCE; } else { throw parameterError(p, "@Part annotation must supply a name or use MultipartBody.Part parameter type."); } } else { Headers headers = Headers.of("Content-Disposition", "form-data; name=\"" + partName + "\"", "Content-Transfer-Encoding", part.encoding()); if (Iterable.class.isAssignableFrom(rawParameterType)) { if (!(type instanceof ParameterizedType)) { throw parameterError(p, rawParameterType.getSimpleName() + " must include generic type (e.g., " + rawParameterType.getSimpleName() + " )"); } ParameterizedType parameterizedType = (ParameterizedType) type; Type iterableType = Utils.getParameterUpperBound(0, parameterizedType); if (MultipartBody.Part.class.isAssignableFrom(Utils.getRawType(iterableType))) { throw parameterError(p, "@Part parameters using the MultipartBody.Part must not " + "include a part name in the annotation."); } Converter converter = retrofit.requestBodyConverter(iterableType, annotations, methodAnnotations); return new ParameterHandler.Part<>(headers, converter).iterable(); } else if (rawParameterType.isArray()) { Class arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType()); if (MultipartBody.Part.class.isAssignableFrom(arrayComponentType)) { throw parameterError(p, "@Part parameters using the MultipartBody.Part must not " + "include a part name in the annotation."); } Converter converter = retrofit.requestBodyConverter(arrayComponentType, annotations, methodAnnotations); return new ParameterHandler.Part<>(headers, converter).array(); } else if (MultipartBody.Part.class.isAssignableFrom(rawParameterType)) { throw parameterError(p, "@Part parameters using the MultipartBody.Part must not " + "include a part name in the annotation."); } else { Converter converter = retrofit.requestBodyConverter(type, annotations, methodAnnotations); return new ParameterHandler.Part<>(headers, converter); } } } else if (annotation instanceof PartMap) { if (!isMultipart) { throw parameterError(p, "@PartMap parameters can only be used with multipart encoding."); } gotPart = true; Class rawParameterType = Utils.getRawType(type); if (!Map.class.isAssignableFrom(rawParameterType)) { throw parameterError(p, "@PartMap parameter type must be Map."); } Type mapType = Utils.getSupertype(type, rawParameterType, Map.class); if (!(mapType instanceof ParameterizedType)) { throw parameterError(p, "Map must include generic types (e.g., Map )"); } ParameterizedType parameterizedType = (ParameterizedType) mapType; Type keyType = Utils.getParameterUpperBound(0, parameterizedType); if (String.class != keyType) { throw parameterError(p, "@PartMap keys must be of type String: " + keyType); } Type valueType = Utils.getParameterUpperBound(1, parameterizedType); if (MultipartBody.Part.class.isAssignableFrom(Utils.getRawType(valueType))) { throw parameterError(p, "@PartMap values cannot be MultipartBody.Part. " + "Use @Part List or a different value type instead."); } Converter valueConverter = retrofit.requestBodyConverter(valueType, annotations, methodAnnotations); PartMap partMap = (PartMap) annotation; return new ParameterHandler.PartMap<>(valueConverter, partMap.encoding()); } else if (annotation instanceof Body) { if (isFormEncoded || isMultipart) { throw parameterError(p, "@Body parameters cannot be used with form or multi-part encoding."); } if (gotBody) { throw parameterError(p, "Multiple @Body method annotations found."); } Converter converter; try { converter = retrofit.requestBodyConverter(type, annotations, methodAnnotations); } catch (RuntimeException e) { // Wide exception range because factories are user code. throw parameterError(e, p, "Unable to create @Body converter for %s", type); } gotBody = true; return new ParameterHandler.Body<>(converter); } return null; // Not a Retrofit annotation. }复制代码
Request build() { HttpUrl url; HttpUrl.Builder urlBuilder = this.urlBuilder; if (urlBuilder != null) { url = urlBuilder.build(); } else { // No query parameters triggered builder creation, just combine the relative URL and base URL. //noinspection ConstantConditions Non-null if urlBuilder is null. url = baseUrl.resolve(relativeUrl); if (url == null) { throw new IllegalArgumentException( "Malformed URL. Base: " + baseUrl + ", Relative: " + relativeUrl); } } RequestBody body = this.body; if (body == null) { // Try to pull from one of the builders. if (formBuilder != null) { body = formBuilder.build(); } else if (multipartBuilder != null) { body = multipartBuilder.build(); } else if (hasBody) { // Body is absent, make an empty body. body = RequestBody.create(null, new byte[0]); } } MediaType contentType = this.contentType; if (contentType != null) { if (body != null) { body = new ContentTypeOverridingRequestBody(body, contentType); } else { requestBuilder.addHeader("Content-Type", contentType.toString()); } } return requestBuilder .url(url) .method(method, body) .build(); }复制代码
接着看看call.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)); }复制代码