Android Retrofit source code reading notes (3)

Retrofit source code reading notes (3)

The first article introduces Retrofitdynamic proxy implementation, method annotation analysis, etc.: Android Retrofit source code reading notes (1) .
The second article introduces Retrofithow to parse the parameters in the method : Android Retrofit source code reading notes (2) .

This article is the third in a series of articles. It introduces Retrofithow to build Httpa request task. I personally think this part of the code is Retrofitthe most complex part of the code and the most core part. Get ready to get on the bus.

Http request task construction

Let's review the previous content. Dynamic proxy methods are all ServiceMethod#invoke()called by calling the method. If there is no cached ServiceMethodobject, it needs to be ServiceMethod#parseAnnotations()constructed by parsing various annotations in the method and various parameter types in the method and return value types. An ServiceMethodobject, which is then called by the proxy method. In ServiceMethod#parseAnnotations()the method, RequestFactory#parseAnnotations()an object will be generated through method parsing RequestFactory, which encapsulates the construction Http Requestmethod (already analyzed in the previous article); then HttpServiceMethod.parseAnnotations()a requested task will be generated through method parsing , that is, the object Httpused in the dynamic proxy will be returned. ServiceMethod, which is also our main content today.

Before starting, let me introduce Kotlinthe coroutine suspendmethod to avoid difficulties in reading the source code later.
Suppose I define a Kotilnmethod like this:

suspend fun helloWorld(): String

After being processed by Kotlinthe compiler, the above method definition becomes as follows at runtime:

fun helloWorld(continuation: Continuation<String>): Any

The return parameter of the method becomes Objectan object. The original function has one more Continuationparameter, and the generic type in it is the return value type of the original function. Therefore, the method of Retrofitjudgment is also to judge whether the last parameter is , as mentioned in the previous article.KotlinsuspendContinuation

HttpServiceMethod#parseAnnotations()Start analyzing from implementation:

  static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    
    
    // 是否是 Kotlin 协程 suspend 方法  
    boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
    // suspend 方法返回值类型是否是 Response
    boolean continuationWantsResponse = false;
    // suspend 方法返回 Response Body 是否可以为空
    boolean continuationBodyNullable = false;
    
    // 获取方法中的注解
    Annotation[] annotations = method.getAnnotations();
    Type adapterType;
    // 如果是 Kotlin suspend 函数
    if (isKotlinSuspendFunction) {
    
    
      Type[] parameterTypes = method.getGenericParameterTypes();
      // 获取 Continuation 参数中的泛型的类型,也就是协程方法返回值的类型
      Type responseType =
          Utils.getParameterLowerBound(
              0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
      // 如果返回值的类型是 Retrofit 中的 Response        
      if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
    
    
        // 获取 Response<T> 中的泛型类型,也就是 Response Body 需要转换的类型
        // Unwrap the actual body type from Response<T>.
        responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
        // 标记想要 Response
        continuationWantsResponse = true;
      } else {
    
    
        // TODO figure out if type is nullable or not
        // Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)
        // Find the entry for method
        // Determine if return type is nullable or not
      }
      // suspend 方法的 adatperType 统一为 Call
      adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
      // 添加 @SkipCallbackExecutor 注解表明后续 CallBack 回调线程在主线程(后面我们会看到这部分代码)
      annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
    } else {
    
    
      // 非 suspend 的方法
      // 直接方法的返回值类型作为 adapterType
      adapterType = method.getGenericReturnType();
    }
    
    // 获取 adapterType 对应的 CallAdapter,也就是通过 CallAdapterFactory 获取对应 adapterType 的实例
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
        
    // 通过 CallAdapter 获取 ResponseBody 转换后的类型   
    Type responseType = callAdapter.responseType();
    
    // Response Type不允许是 OkHttp 中的 Response
    if (responseType == okhttp3.Response.class) {
    
    
      throw methodError(
          method,
          "'"
              + getRawType(responseType).getName()
              + "' is not a valid response body type. Did you mean ResponseBody?");
    }
    // Response Type 不允许是 Retrofit 中的 Response
    if (responseType == Response.class) {
    
    
      throw methodError(method, "Response must include generic type (e.g., Response<String>)");
    }
    // TODO support Unit for Kotlin?
    // 如果是 HEAD 请求,Response Type 只能是 Void
    if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
    
    
      throw methodError(method, "HEAD method must use Void as response type.");
    }
    // 获取 ResponseBody 到 Response Type 的 Converter
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);
    // 这个 okhttp3.Call.Factory 其实就是 OkhttpClient
    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    if (!isKotlinSuspendFunction) {
    
    
      // 非 suspend 函数
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    } else if (continuationWantsResponse) {
    
    
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      // 返回值为 Response 的 suspend 函数
      return (HttpServiceMethod<ResponseT, ReturnT>)
          new SuspendForResponse<>(
              requestFactory,
              callFactory,
              responseConverter,
              (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
    } else {
    
    
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      // 返回值不为 Response 的 suspend 函数。
      return (HttpServiceMethod<ResponseT, ReturnT>)
          new SuspendForBody<>(
              requestFactory,
              callFactory,
              responseConverter,
              (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
              continuationBodyNullable);
    }
  }

Let’s clarify what was mentioned above adapterType(some local codes are also called returnType) and responseType. There are two situations here, one is a coroutine method, and the other is not a coroutine method. Let me give you an example.

Coroutine method:

interface MyService {
    
    
    @GET("/foo1")
    suspend fun foo1(): String

    @GET("/foo2")
    suspend fun foo2(): Response<String>
}

The fix in the coroutine method adapterTypeis Call(the here Callis Retrofitdefined in , pay attention to the difference OkHttpwith Callthe , the interface Retrofitin is similar to the , but is simply encapsulated)CallOkHttpCall

The above foo1()and foo2()theirs responseTypeare all String, that is, the coroutine method foo1()in the source code does not require , but the coroutine method that requires .Responsefoo2()Response

Non-coroutine method:

interface MyService {
    
    
    @GET("/foo1")
    fun foo1(): Call<String>

    @GET("/foo2")
    fun foo2(): Single<String>
}

foo1()’s adapterTypeis Call, and foo2()adapterTypes is Single, theirs responseTypeare String.

Through the above examples, I believe you can already distinguish between adapterTypeand in different situations responseType. Then let's analyze the logic in the source code.

Coroutine method:

  1. If the return value Responseis then it is Responsethe coroutine method that requires , and its is adatperTypefixed to Call, responseTypewhich is Responsethe generic type in .
  2. If the return value is not Response, then it is an unnecessary Responsecoroutine method. adapterTypeFixed to Call, responseTypefixed to the coroutine method return value.
  3. The coroutine method will add an annotation to the original annotation @SkipCallbackExecutor. This annotation indicates that the subsequent callback is in the main thread (we will see this logic later). If the thread in is not added OkHttpby default.Dispatcher

Non-coroutine method:

  1. The return type of the method is directly adapterType, and the generic type of the return type is responseType(to be precise, it is CallAdapterreturned, but this condition is almost always met.)

Common logic for coroutine methods and non-coroutine methods:

  1. Obtain adapterTypethe corresponding instance CallAdapter, that is , CallAdapterobtain the corresponding instance through , the default only supports ( ).adapterTypeCallAdapterCallAdapterFactoryCallAdapterRxJavaLiveDataCallAdapterFactoryCallRetrofit
  2. Must be empty if HEADrequested .responseType
  3. responseTypeIt can't be Reponse. (Including those in OkHttpand )RetrofitResponse
  4. Get RequestBodytransferred . responseType_Converter
  5. Build different ServiceMethodimplementations based on different method types. Ordinary methods: CallAdapted; Coroutine requires Resposne: SuspendForResponse; Coroutine does not require Response: SuspendForBody.

Implementation of OkHttpCall

As mentioned in the previous section, all method types ServiceMethodare implemented by the three objects of CallAdapted, SuspendForResponseand , SuspendForResponseand their common parent class is HttpServiceMethod, and HttpServiceMethodthe parent class of is ServiceMethod.

The final method call is through ServiceMethod#invoke()the method, which is an abstract method, and the implementation is HttpServiceMethod#invoke()the method. Let's take a look at its implementation first:

  @Override
  final @Nullable ReturnT invoke(Object[] args) {
    
    
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }

We see that this constructs an Callobject, and its implementation class is OkHttpCall, which is similar to the one OkHttpin . The method is an asynchronous call or a synchronous call. If yes , the final returned implementation is , and we can see this part of the code when we analyze the code later .ReallCallenqueue()execute()adapterTypeCallCallOkHttpCallDefaultCallAdapterFactory

OkHttpCallSynchronous call

Let’s first look at the implementation of the synchronous call method OkHttpCall#execute():

  @Override
  public Response<T> execute() throws IOException {
    
    
    okhttp3.Call call;

    synchronized (this) {
    
    
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;
      // 构建 OkHttp 中的 Call
      call = getRawCall();
    }

    if (canceled) {
    
    
      call.cancel();
    }
    // 解析 OkHttp 的 Response 为 Retrofit 的 Response
    return parseResponse(call.execute());
  }

Use getRawCall()the method to build OkHttpin Call, execute it synchronously Call#execute()( OkHttp), and then use parseResponse()the method to get the parsed OkHttpin Responseto be Retrofitin Response.

First look at getRawCall()the source code of the method:

  @GuardedBy("this")
  private okhttp3.Call getRawCall() throws IOException {
    
    
    okhttp3.Call call = rawCall;
    // 如果已经创建 OkHttp.Call 直接使用。
    if (call != null) return call;

    // Re-throw previous failures if this isn't the first attempt.
    if (creationFailure != null) {
    
    
      if (creationFailure instanceof IOException) {
    
    
        throw (IOException) creationFailure;
      } else if (creationFailure instanceof RuntimeException) {
    
    
        throw (RuntimeException) creationFailure;
      } else {
    
    
        throw (Error) creationFailure;
      }
    }

    // Create and remember either the success or the failure.
    try {
    
    
      // 创建 OkHttp.Call
      return rawCall = createRawCall();
    } catch (RuntimeException | Error | IOException e) {
    
    
      throwIfFatal(e); // Do not assign a fatal error to creationFailure.
      creationFailure = e;
      throw e;
    }
  }

Creation OkHttp.Callis through createRawCall()the method, let's continue to see the implementation:

  private okhttp3.Call createRawCall() throws IOException {
    
    
    okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
    if (call == null) {
    
    
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }

callFactoryThe implementation of the above is OkHttpClientactually to call OkHttpClient#newCall()the method to create one RealCall; and RequestFactory, as we introduced in the first and second articles, OkHttp.Requestthe objects used to generate after parsing various annotations, we see that it The parameters are passed to RequestFactory#create()the method, and then the object is generated OkHttp.Request. Let's take a look at its source code implementation:

  okhttp3.Request create(Object[] args) throws IOException {
    
    
    @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
    // 获取所有的参数处理器
    ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;

    int argumentCount = args.length;
    // 参数的数量不正确,报错。  
    if (argumentCount != handlers.length) {
    
    
      throw new IllegalArgumentException(
          "Argument count ("
              + argumentCount
              + ") doesn't match expected count ("
              + handlers.length
              + ")");
    }
    
    // 构建一个 RequestBuilder
    RequestBuilder requestBuilder =
        new RequestBuilder(
            httpMethod,
            baseUrl,
            relativeUrl,
            headers,
            contentType,
            hasBody,
            isFormEncoded,
            isMultipart);
    // 如果是协程方法,需要参数数量减一。
    if (isKotlinSuspendFunction) {
    
    
      // The Continuation is the last parameter and the handlers array contains null at that index.
      argumentCount--;
    }

    List<Object> argumentList = new ArrayList<>(argumentCount);
    // 遍历参数处理器,填充请求的数据到 RequestBuilder 中。
    for (int p = 0; p < argumentCount; p++) {
    
    
      argumentList.add(args[p]);
      handlers[p].apply(requestBuilder, args[p]);
    }
    
    // 构建 okHttp.Request
    return requestBuilder.get().tag(Invocation.class, new Invocation(method, argumentList)).build();
  }

Briefly describe:

  1. Check whether ParameterHandlerthe quantity of and argsthe quantity of are consistent.
  2. Build RequestBuilderobject.
  3. If it is suspenda function, you need to reduce the number of parameters by one. The reason is as described in my previous suspenddescription of the function.
  4. Traverse ParameterHandlerand fill the requested data into the RequestBuilder.
  5. Construct Request.

Let’s look at the implementation OkHttp.Responseof the parsing parseResponse()method:

  Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    
    
    // 提取 Response Body
    ResponseBody rawBody = rawResponse.body();

    // Remove the body's source (the only stateful object) so we can pass the response along.
    // 构建新的 Response,但是移除了 ResponseBody
    rawResponse =
        rawResponse
            .newBuilder()
            .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
            .build();

    int code = rawResponse.code();
    
    // 不为 200+,请求都表示失败
    if (code < 200 || code >= 300) {
    
    
      try {
    
    
        // Buffer the entire body to avoid future I/O.
        ResponseBody bufferedBody = Utils.buffer(rawBody);
        return Response.error(bufferedBody, rawResponse);
      } finally {
    
    
        rawBody.close();
      }
    }
    // 204,205 RequestBody 固定为空
    if (code == 204 || code == 205) {
    
    
      rawBody.close();
      return Response.success(null, rawResponse);
    }
    
    // 构建新的 ResponseBody,拦截读取过程中的异常
    ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
    try {
    
    
      // 通过 Converter 将 ResponseBody 转换成 responseType
      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.
      // 抛出读取 ResponseBody 时发生的错误。
      catchingBody.throwIfCaught();
      throw e;
    }
  }

To summarize the parsing RepsonseBodyprocess:

  1. Extract ResposneBody, build a new one Response, but remove it ResponseBody.
  2. Response CodeIf it is not 200+, it means the request failed.
  3. Response CodeIt is 204 or 205 and cannot be read ResponseBody.
  4. Pass Converter, ResponseBodyconvert to responseType.

OkHttpCallasynchronous call

Look directly OkHttpCall#enqueue()at the source code:

  @Override
  public void enqueue(final Callback<T> callback) {
    
    
    Objects.requireNonNull(callback, "callback == null");

    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 {
    
    
          // 创建 `OkHttp.Call`
          call = rawCall = createRawCall();
        } catch (Throwable t) {
    
    
          throwIfFatal(t);
          failure = creationFailure = t;
        }
      }
    }

    if (failure != null) {
    
    
      // 回调 `OkHttp.Call` 创建失败
      callback.onFailure(this, failure);
      return;
    }

    if (canceled) {
    
    
      call.cancel();
    }
    // OkHttp.Call 的异步调用
    call.enqueue(
        new okhttp3.Callback() {
    
    
          @Override
          public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
    
    
            Response<T> response;
            try {
    
    
              // 解析 Response
              response = parseResponse(rawResponse);
            } catch (Throwable e) {
    
    
              throwIfFatal(e);
              callFailure(e);
              return;
            }

            try {
    
    
              // 回调成功
              callback.onResponse(OkHttpCall.this, response);
            } catch (Throwable t) {
    
    
              throwIfFatal(t);
              t.printStackTrace(); // TODO this is not great
            }
          }

          @Override
          public void onFailure(okhttp3.Call call, IOException e) {
    
    
          
            // 回调失败
            callFailure(e);
          }

          private void callFailure(Throwable e) {
    
    
            try {
    
    
              // 回调失败
              callback.onFailure(OkHttpCall.this, e);
            } catch (Throwable t) {
    
    
              throwIfFatal(t);
              t.printStackTrace(); // TODO this is not great
            }
          }
        });
  }

The code for asynchronous calls is also createRawCall()generated through the method OkHttp.Calland parseResponse()parsed through the method OkHttp.Response. These two key methods have been analyzed during synchronous calls. The code for asynchronous calls is also very simple. Just take a look at it yourself.

OkHttpCallSummarize

OkHttpCallThat is, the core encapsulation of requests Retrofitin , and the default implementation also directly returns the current implementation. Like other task encapsulation, such as , etc., they are also based on the implementation of deformation.HttpDefaultCallAdapterFactoryOkHttpCallCallRxJavaLiveDataOkHttpCall

Implementation of CallAdapted

The proxy's method call ServiceMethod#invoke()is implemented by calling HttpServiceMethod#invoke()the method, which creates an OkHttpCallobject (analyzed earlier), and then calls adapt()the method to pass this object to its implementation class, which adapt()is an abstract method, CallAdaptedand SuspendForResponsethey SuspendForBodyimplement different adapt()methods respectively.

Take a look at CallAdapted#adapt()the implementation of the method:

    @Override
    protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
    
    
      return callAdapter.adapt(call);
    }

Directly call callAdapterthe adapt()method, which callAdapteris obtained adapterTypefrom CallAdapterFactory(it can be Retrofitcustomized when building the instance). Our Calltype adapterTypeis obtained directly DefaultCallAdapterFactoryfrom callAdapter.

Let’s look directly at DefaultCallAdapterFactory#get()the implementation of the method:

  @Override
  public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
    
    
    // adapterType 必须为 Call  
    if (getRawType(returnType) != Call.class) {
    
    
      return null;
    }
    // Call 中必须有具体的泛型类型
    if (!(returnType instanceof ParameterizedType)) {
    
    
      throw new IllegalArgumentException(
          "Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
    }
    // 获取 ReponseType
    final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);
    
    // 判断是否有 @SkipCallbackExecutor 注解,如果有就表示需要在主线程回调,前面在分析协程那部分是提到过。
    final Executor executor =
        Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
            ? null
            : callbackExecutor;
    // 构建匿名的 CallAdapter 对象
    return new CallAdapter<Object, Call<?>>() {
    
    
      @Override
      public Type responseType() {
    
    
        return responseType;
      }

      @Override
      public Call<Object> adapt(Call<Object> call) {
    
    
        // 如果不需要在新的线程中回调,直接返回 OkHttpCall,反之用ExecutorCallbackCall 封装一下。
        return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
      }
    };
  }

To summarize the above logic:

  1. adapterTypemeans Callthat the current one CallAdapterFactorycan be processed, otherwise it cannot be processed, and if the return is empty, the system will find the next one that can be processed CallAdapterFacotry.
  2. Get Callthe generic type of as responseType.
  3. If there is @SkipCallbackExecutoran annotation (mentioned when talking about coroutine methods), it means that the callback needs to be made on the main thread.
  4. Construct an anonymous CallAdapterobject. adapt()If the method needs to be called back in the main thread, it needs to be ExecutorCallbackCallencapsulated OkHttpCall. Otherwise OkHttpCall, it will be returned directly. adapt()The return value of the method is also ServiceMethod#invoke()the return value of the final method and the return value of the final proxy method.

Implementation of SuspendForResponse

Let’s look directly at SuspendForResponse#adapt()the implementation of the method:

    @Override
    protected Object adapt(Call<ResponseT> call, Object[] args) {
    
    
      // 这个 callAdapter 一定是由 DefaultCallAdapterFactory 生成的,因为协程方法的 adaptType 一定是 Call
      call = callAdapter.adapt(call);

      //noinspection unchecked Checked by reflection inside RequestFactory.
      // 获取协程方法必须的 Continuation 参数
      Continuation<Response<ResponseT>> continuation =
          (Continuation<Response<ResponseT>>) args[args.length - 1];

      // See SuspendForBody for explanation about this try/catch.
      try {
    
    
        // 调用协程方法,这个实现的代码是 Kotlin
        return KotlinExtensions.awaitResponse(call, continuation);
      } catch (Exception e) {
    
    
        return KotlinExtensions.suspendAndThrow(e, continuation);
      }
    }

To summarize the above code:

  1. callAdapterMust be DefaultCallAdapterFactorygenerated by , because the coroutine method adaptTypemust be Call.
  2. Get Continuationthe parameters, which are required for coroutine method calls.
  3. KotlinExtensions.awaitResponse()Coroutine methods are called via the method, which is Kotlinwritten by .

Continue to look at KotlinExtensions.awaitResponse()the source code:

suspend fun <T> Call<T>.awaitResponse(): Response<T> {
    
    
  return suspendCancellableCoroutine {
    
     continuation ->
    continuation.invokeOnCancellation {
    
    
      cancel()
    }
    enqueue(object : Callback<T> {
    
    
      override fun onResponse(call: Call<T>, response: Response<T>) {
    
    
        continuation.resume(response)
      }

      override fun onFailure(call: Call<T>, t: Throwable) {
    
    
        continuation.resumeWithException(t)
      }
    })
  }
}

If you don’t know Callbackthe conversion suspendmethod, it is recommended to search for information online, OkHttpCall#enqueue()trigger the request directly through the method, and then convert it into the coroutine method. Pay attention to the ( ) suspendreturned directly here .ResponseRetrofit

Implementation of SuspendForBody

SuspendForBody#adapt()Implementation of method:

    @Override
    protected Object adapt(Call<ResponseT> call, Object[] args) {
    
    
      call = callAdapter.adapt(call);

      //noinspection unchecked Checked by reflection inside RequestFactory.
      Continuation<ResponseT> continuation = (Continuation<ResponseT>) args[args.length - 1];
      try {
    
    
        return isNullable
            ? KotlinExtensions.awaitNullable(call, continuation)
            : KotlinExtensions.await(call, continuation);
      } catch (Exception e) {
    
    
        return KotlinExtensions.suspendAndThrow(e, continuation);
      }
    }

It can be said that it is almost SuspendForResponseexactly the same as the code in , except that an empty judgment is added. The coroutine method call that is not empty in the end is KotlinExtensions.await()the method called. Let's take a look at its implementation:

@JvmName("awaitNullable")
suspend fun <T : Any> Call<T?>.await(): T? {
    
    
  return suspendCancellableCoroutine {
    
     continuation ->
    continuation.invokeOnCancellation {
    
    
      cancel()
    }
    enqueue(object : Callback<T?> {
    
    
      override fun onResponse(call: Call<T?>, response: Response<T?>) {
    
    
        if (response.isSuccessful) {
    
    
          continuation.resume(response.body())
        } else {
    
    
          continuation.resumeWithException(HttpException(response))
        }
      }

      override fun onFailure(call: Call<T?>, t: Throwable) {
    
    
        continuation.resumeWithException(t)
      }
    })
  }
}

The implementation is basically the same KotlinExtensions.awaitResponse()as , except that the final return value is taken ResponseBody(converted into returnType) ResponseBody.

Summarize

RetrofitThe two core logics of Http Requestthe construction of and Httpthe construction of the request task have also been run through, and basically the entire process has been strung together. I am going to write another article later to introduce Moshihow the and ConverterFactoryof work, for those who want to customize and Some references for classmates.RxJavaCallAdapterFactoryConverterFactoryCallAdapterFactory

at last

If you want to become an architect or want to break through the 20-30K salary range, then don't be limited to coding and business, you must be able to select and expand, and improve your programming thinking. In addition, good career planning is also very important, and learning habits are important, but the most important thing is to be able to persevere. Any plan that cannot be implemented consistently is empty talk.

If you have no direction, here is a set of "Advanced Notes on the Eight Modules of Android" written by a senior architect at Alibaba to help you systematically organize messy, scattered, and fragmented knowledge, so that you can systematically and efficiently Master various knowledge points of Android development.
img
Compared with the fragmented content we usually read, the knowledge points in this note are more systematic, easier to understand and remember, and are strictly arranged according to the knowledge system.

Welcome everyone to support with one click and three links. If you need the information in the article, just scan the CSDN official certification WeChat card at the end of the article to get it for free↓↓↓ (There is also a small bonus of ChatGPT robot at the end of the article, don’t miss it)

PS: There is also a ChatGPT robot in the group, which can answer everyone’s work or technical questions.

picture

Guess you like

Origin blog.csdn.net/Androiddddd/article/details/135175102