Android Retrofit source code analysis

Retrofit usage

Retrofit request annotation

Serial numbernameexplain
1GETget request
2POSTpost request
3PUTput request
4DELETEdelete request
5PATCHpatch request, which is a supplement to put request and is used to update local resources
6HEADhead request
7OPTIONSoption request
8HTTPThe general annotation can replace all the above annotations. It has three attributes: method, path and hasBody

Retrofit Parameter annotation

classificationnameexplain
Act on methodHeadersIt is used to add fixed request headers. Multiple can be added at the same time. The request headers added through this annotation will not overlap each other, but exist together
Parameters acting on method parametersHeaderPassed as a parameter of the method, it is used to add an unfixed Header. This annotation will update the existing request Header
Request parametersBodyIt is mostly used for sending non form data in post request, such as transferring json format data in post mode
Request parametersFieldYou need to use the fields of URL and fileencoded in the request form to add multiple fields
Request parametersFieldMapForm fields, together with Field and FormUrlEncoded, receive map < String, String > types. Non String types will call toString() method
Request parametersPartIt is used for form fields. Part, PartMap and Multipart annotations are used together. It is suitable for file upload
Request parametersPartMapThe form field, matched with Part, is suitable for file upload. By default, it receives the type of map < string, RequestBody >, and non RequestBody will be converted through Converter
Request parametersHeaderMapUsed for URL, add request header
Request parametersPathIt is used as a placeholder in the url. The path has parameters, such as project/{id}/list. Where id is a placeholder parameter, use @ Path("Id") id:Int to complete the parameter
Request parametersQueryUsed to set parameters in Get request
Request parametersQueryMapSimilar to Query
Request parametersUrlSpecify the path of the request

Retrofit tag annotation

classificationnameexplain
Request parametersFormUrlEncodedIndicates that the request entity is a Form, and each key value pair needs @ Field annotation
Request parametersMultipartIndicates that the requesting entity is a Form that supports file upload and needs to be used together. @ Part is applicable to scenarios with file upload
signStreamingThe data representing the response body is returned in the form of stream, which is applicable to the large returned data. This annotation is particularly useful when downloading large files
  • Usage of uploaded files @ Multipart annotation
interface AndroidApi {

    //Upload pictures
    @Multipart
    @POST("project/upload")
    fun upload(@Part file: MultipartBody.Part): Call<RequestBody>


    //Upload multiple pictures
    @Multipart
    @POST("project/upload")
    fun uploadMulti(@PartMap map: Map<String, MultipartBody.Part>): Call<RequestBody>

}
	//Single picture upload
    fun testUpload(path: String) {
        val file = File(path)
        val requestBody = file.asRequestBody("image/png".toMediaTypeOrNull())
        val filePart = MultipartBody.Part.createFormData("key", file.name, requestBody)
        val call = androidApi.upload(filePart)
        call.execute()
    }

	//Multi map upload
    fun testUploadMulti(files: List<File>) {
        val map = mutableMapOf<String, RequestBody>()
        files.forEach { file ->
            val requestBody = file.asRequestBody("image/png".toMediaTypeOrNull())
            map["file\";filename=\"test.png"] = requestBody
        }
        androidApi.uploadMulti(map)
    }
    
interface AndroidApi {

    //The data representing the response body is returned in the form of stream, which is applicable to large returned data. This annotation is particularly useful when downloading large files
    @Streaming
    @GET
    fun downloadFile(@Url fileUrl:String):Call<RequestBody>

}

Annotation by reflection

  • First, use the isAnnotationPresent() method of the Class object to determine whether it applies an annotation
	javaClass.isAnnotationPresent(Nullable::class.java)
  • Then get the Annotation object through getAnnotation() or getAnnotations() methods

Parsing process of Retrofit annotation

  • Use the code on the process
    private fun retrofitTest() {
        //Generate retrofit instance
        val retrofit = Retrofit.Builder()
            .baseUrl("http://image.so.com/")
            .addConverterFactory(GsonConverterFactory.create())
            .build()

        //Create apiService instance
        val realApi = retrofit.create(RealApi::class.java)

		//Request specific interface
        realApi.getPicData(name, startNum, pageNum)
            .enqueue(object : Callback<RealPic?>() {
                fun onResponse(call: Call<RealPic?>?, response: Response<RealPic?>) {
                    
                }

                fun onFailure(call: Call<RealPic?>?, t: Throwable?) {
                    
                }
            })
    }
  1. Retrofit.Builder
    Creating Retrofit objects through builder mode
  2. Retrofit.create
    Pass in a custom interface service, including methods and annotations
    Create an instance proxy of the interface through dynamic proxy newProxyInstance
  3. loadServiceMethod
    Through reflection, the defined annotation is parsed to generate a ServiceMethod object and cached
    Parsing of RequestFactory annotation
    Assemble the RequestBuilder annotation and assemble it as the Request of OKhttp
  4. new OkHttpCall<>
    Create OkHttpCall object, implement call interface and adapt okhttp3 Call
  5. T adapt(Call<> call)
    Take the CallAdapter from the callAdapterFactories collection of Retrofit and call the adapt method. If it is the default, use ExecutorCallAdapterFactory to adapt and return call < >. If it is RxJavaCallAdapterFactory, return Observable
  6. enqueue
    Execute the specific request. After the request is completed, submit the Runnable to the main thread through the mainthreadexecution

Subsystem provided by Retrofit (appearance mode)

  1. serviceMethodCache (custom interface mapping object collection)
  2. baseUrl (request address)
  3. callFactory (OKHttpCall by default)
  4. converterFactories (data parser factory collection)
  5. callAdapterFactories (collection of Call adapter factories)
  6. callbackExecutor (callback execution, mainthreadexecution by default for Android platform)
  • Using the Builder model to build, the parts that the object depends on are created, assembled and encapsulated, so that the client can easily obtain a complex object.

ServiceMethod

  • ServiceMethod is a request method in an interface
  • For the network Request object mapped by the interface, the label of the user-defined interface is converted into the object through the dynamic agent, and the label and parameters are generated into the Request object required by OkHttp. Retrofit.create intercepts through dynamic proxy, converts each custom interface method into a ServiceMethod object, and caches it through ServiceMethodCache.
  public <T> T create(final Class<T> service) {
    validateServiceInterface(service);
    return (T)
        Proxy.newProxyInstance(
            service.getClassLoader(),
            new Class<?>[] {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 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;
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
              }
            });
  }

Keywords: Retrofit

Added by taiger on Fri, 11 Feb 2022 10:51:24 +0200