Take SandwichDemo as an example.Making the address
Create a Retrofit
-
private val retrofit: Retrofit = Retrofit.Builder() .client(okHttpClient) .baseUrl( "https://gist.githubusercontent.com/skydoves/aa3bbbf495b0fa91db8a9e89f34e4873/raw/a1a13d37027e8920412da5f00f6a89c5a3dbfb 9a/" ) .addConverterFactory(GsonConverterFactory.create()) /* asynchronous supports */ // .addCallAdapterFactory(DataSourceCallAdapterFactory.create()) /* coroutines supports */ .addCallAdapterFactory(CoroutinesResponseCallAdapterFactory.create()) //.addCallAdapterFactory(CoroutinesDataSourceCallAdapterFactory.create()) .build() Copy the code
Creating an interface Class
val disneyService: DisneyCoroutinesService = retrofit.create(DisneyCoroutinesService::class.java) Copy the code
Gets the data returned by the interface
val apiResponse:ApiResponse<List<Poster>> = disneyService.fetchDisneyPosterList() Copy the code
It’s as simple as that. Data acquisition is done
Analysis of subdivision process
-
- create
Retrofit
. The creator mode is used hereRetrofit.Builder
To create aRetrfofit
Example, in general projects will be made singleton Builder().client(OkHttpClient client)
Sets the final caller of the network request, here andOkHttp
Is a piece of my heartbaseUrl(Url baseUrl)
Set up thebaseUrl
linkaddConverterFactory(Converter.Factory factory)
Add network parameters and return converters to classes, for exampleGson,Moshi
Etc.addCallAdapterFactory(CallAdapter.Factory factory)
Adds a converter to the interface request resultbuild()
Method, will passplatform.defaultCallAdapterFactories(callbackExecutor)
To add the defaultCallAdapter.Factory
Converters and our custom converters. whileConvertorFactory
Converter, added by defaultnew BuiltInConverters()
And platform default convertersplatform.defaultConverterFactories()
And our custom converter
- create
-
1. Call the create(Class
service) method to create the corresponding interface Class
return(T) Proxy.newProxyInstance( service.getClassLoader(), new Class<? >[] {service}, new InvocationHandler() {private final Platform platform = Platform.get(a);private final Object[] emptyArgs = new Object[0]; @Override public @Nullable 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); } args = args ! =null ? args : emptyArgs; returnplatform.isDefaultMethod(method) ? platform.invokeDefaultMethod(method, service, proxy, args) : loadServiceMethod(method).invoke(args); }});Copy the code
This is done by dynamic proxy. There are many theories of dynamic proxy on the web, you can search for them yourself; The invoke() of InvocationHandler is invoked by the dynamic proxy class. Method provides methods of method, and args provides parameters of method. Here you are completely proxying the interface method to implement it yourself, and the stage is as big as the idea is.
-
Invoke method resolution
- parsing
loadServiceMethod(method).invoke(args)
.loadServiceMethod()
Method returnsServiceMethod
Abstract class, actuallyHttpServiceMethod
Class. - Core method
HttpServiceMethod.parseAnnotations
Method is called and returnsHttpServiceMethod
Class, here is the core parsing method; The aboveinvoke(args)
The method is finally calledHttpServiceMethod
Of the classinvoke
Method, which is eventually called as follows:
@Override final @Nullable ReturnT invoke(Object[] args) { Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter); return adapt(call, args); } Copy the code
Address the HttpServiceMethod
,>
.parseAnnotations() method: The parameters and return values are parsed using the RequestFactory, Java if (utils.getrawType (parameterType) == continuation. class) {isKotlinSuspendFunction = true; return null; } This parsing determines whether it is a suspend function. Different return values are determined depending on whether the function is suspended or not. Continue: Get the corresponding adapterType, such as the UserData type in Call
or the UserData return value from suspend, depending on whether it is a suspended function.
CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method, adapterType, annotations); Type responseType = callAdapter.responseType(); Copy the code
Here, the return type matches the CallAdapter we added to wrap or logic the Response returned
Converter<ResponseBody, ResponseT> responseConverter = createResponseConverter(retrofit, method, responseType); Copy the code
Here we use responseType to get the return result converter we added, such as GsonFactory,MothiFactory, and 4.
if(! isKotlinSuspendFunction) {return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter); } else if (continuationWantsResponse) { //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object. return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForResponse<>( requestFactory, callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter); } else { //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object. return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForBody<>( requestFactory, callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter, continuationBodyNullable); } Copy the code
So this is going to return the end of the various HttpMethod implementation classes and if it’s not suspend, it’s going to go straight back to the CallAdapter and in this case, Java code that’s not coroutines is generally the case; SuspendForResponse is returned if the suspend function returns a Response value. SuspendForResponse is returned if the suspend function returns a Response value, which is normally the case in kotlin+ coroutines. SuspendForBody: Suspend automatically calls the OkHttp request interface method in adapt and returns a Response. The CallAdapter must be invoked by the user.
At this point, the abbreviated Version of the Retrofit process has been combed out
Our own parts: you can customize ConverterFactory, CallFactory official here are given default and commonly used, for example the Converter transform class have gson, guava, Jackson, moshi, jaxb… ; And the default CallFactory, in addition to the Treasury’s own default DefualtCallFactory, library and official wrote: guava, java8, rxjava, rxjava2, rxjava3, scala, commonly used here is rxjava2, rxjava3, And such as I now use the Sandwich garage encapsulation CoroutinesResponseCallAdapterFactory and kotlin coroutines combination is very nice
- parsing