An overview of the
Retrofit is a type-safe network request framework for the Android and Java platforms. Retrofit is an encapsulation of a RESTful HTTP Web request framework. Network request work is essentially done by OkHttp, while Retrofit is only responsible for encapsulating the network request interface, which can be used in combination with Rxjava, coroutines, and LiveData. The serialized data returned can be Gson, Jackson, Moshi, Protobuf, and so on
The source code to use
Create and use
Also created from the schema Builder, you can specify BaseUrl, OkHttpClient, adapter, and sequence number factory
- Create a Retrofit
Retrofit retrofit=new Retrofit.Builder()
.baseUrl(baseUrl)
.client(new OkHttpClient())
// Specify the Rxjava adapter
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
// Specify the serialization structure
.addConverterFactory(GsonConverterFactory.create())
.build();
Copy the code
- Create the interface
public interface ApiService {
@GET("/wxarticle/list")
Call<ResponseBody> getNetData(a);
@GET("/wxarticle/list")
Observable<ResponseBody> getNetData2(a);
}
Copy the code
- request
/ / create ApiService
ApiService apiService = retrofit.create(ApiService.class);
// Use the original built-in request
retrofit2.Call<NetData> netData = apiService.getNetData();
netData.enqueue(new retrofit2.Callback<NetData>() {
@Override
public void onResponse(retrofit2.Call<NetData> call, retrofit2.Response<NetData> response) {}@Override
public void onFailure(retrofit2.Call<NetData> call, Throwable t) {}});// ADAPTS the request to the Rxjava stream
apiService.getNetData2()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(data -> {
}, error -> {
});
Copy the code
parsing
Create the Builder.build method for Retrofit
public Retrofit build(a) {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
// The factory mode is used here, but only an OkHttpClient is new
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
// Because in Android platform is Android, platform is an internal class android
callbackExecutor = platform.defaultCallbackExecutor();
}
// This is to add all adapters. The adapter pattern used here is to adapt calls from Okhttp to Retrofit
/ / can also add our own adapter, such as RxJava2CallAdapterFactory. The create (), Rxjava.
// You can also add coroutines or LiveData
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
// This is a javabean conversion class, Gson, Moshi, Protobuf,
List<Converter.Factory> converterFactories =
new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());
// Implement Retrofit constructors
return new Retrofit(
callFactory,
baseUrl,
unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories),
callbackExecutor,
validateEagerly);
}
// Create the APIService, using the dynamic proxy mode, creating an object at run time
public <T> T create(final Class<T> service) {
validateServiceInterface(service);
return (T)
Proxy.newProxyInstance(
service.getClassLoader(),
newClass<? >[] {service},new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// If it comes from the Object method, continue with the original logic
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args); } args = args ! =null ? args : emptyArgs;
The isDefaultMethod() method returns false by default on Android. Because we're using the method in the interface
// The default method in the interface is not called
//Java 8 introduces a new language feature, Default Methods
// Invoke loadServiceMethod(method).invoke(args)
returnplatform.isDefaultMethod(method) ? platform.invokeDefaultMethod(method, service, proxy, args) : loadServiceMethod(method).invoke(args); }}); }// return a ServiceMethod and execute the methodServiceMethod<? > loadServiceMethod(Method method) {// Take it from the cache first, return it directlyServiceMethod<? > result = serviceMethodCache.get(method);if(result ! =null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
// Use reflection, so cache a copy
// HttpServiceMethod, a subclass of ServiceMethod, is returned
result = ServiceMethod.parseAnnotations(this, method); serviceMethodCache.put(method, result); }}return result;
}
Copy the code
HttpServiceMethod: Retorfit annotation parameters and urls are converted to Okhttp Requst, there are respones that come back, and there are requests that are adapted here, and adapted to various return values. By default, Okhttp calls are adapted to Retrofit calls. Or Rxjava Observables, or coroutines, and serializations are all transformed here
Look at the request, look at the default, don’t look at Rxjava, look at how Retrofit calls are converted to Okhttp calls
When we execute, we go to invoke in HttpServiceMethod
abstract class HttpServiceMethod<ResponseT.ReturnT> extends ServiceMethod<ReturnT> {
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations( Retrofit retrofit, Method method, RequestFactory requestFactory) {
// Is the coroutine method in Kotlin
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
boolean continuationWantsResponse = false;
boolean continuationBodyNullable = false;
// Get all the annotations
Annotation[] annotations = method.getAnnotations();
// Get the return type
Type adapterType;
// The coroutine,
if (isKotlinSuspendFunction) {
Type[] parameterTypes = method.getGenericParameterTypes();
Type responseType =
Utils.getParameterLowerBound(
0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
// Unwrap the actual body type from Response<T>.
responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
continuationWantsResponse = true;
} else {
}
adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
// Get the return type
adapterType = method.getGenericReturnType();
}
// This will go to Retrofit's nextCallAdapter method, which iterates through the collection of adapters we set up to get the return type
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
// Get the return serialization type, which is used to find the serialization method
Type responseType = callAdapter.responseType();
if (responseType == okhttp3.Response.class) {
}
if (responseType == Response.class) {
throw methodError(method, "Response must include generic type (e.g., Response<String>)");
}
if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
throw methodError(method, "HEAD method must use Void as response type.");
}
// Get the converterFactories collection that you set up
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if(! isKotlinSuspendFunction) {// Call Best-in-line (undefined) call best-in-line (undefined) call best-in-line (undefined)
return newCallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter); }}}Copy the code
The OkHttpCall encapsulates the Okhttp Call. When we call the request, we are actually calling the Okhttp request
final class OkHttpCall<T> implements Call<T> {
@Override
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
// Get the Okhttp call
okhttp3.Call call;
Throwable failure;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) {
try {
// The new Call from OkhttpClient is used by default. As described above, the factory is used, but the OkhttpClient is still new
call = rawCall = createRawCall();
} catch(Throwable t) { throwIfFatal(t); failure = creationFailure = t; }}}// Invoke the request
call.enqueue(
new okhttp3.Callback() {
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
// After the request succeeds, the request is parsed and the actual lock is returned
response = parseResponse(rawResponse);
} catch (Throwable e) {
throwIfFatal(e);
callFailure(e);
return;
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace(); // TODO this is not great}}}); }}// Parse the return value
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
try {
// responseConverter is the default converter, and GsonRequestBodyConverter can be serialized to the corresponding format
T body = responseConverter.convert(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
// If the underlying source threw an exception, propagate that rather than indicating it was
// a runtime exception.
catchingBody.throwIfCaught();
throwe; }}Copy the code