Retrofit 학습 노트-간단 한 사용 과 소스 분석 은 okhttp 와 관련 이 없습니다.

92398 단어 android지식 공유
인터페이스 클래스 사용
public interface ApiServer {
    String baseUrl="https://wanandroid.com/";

    //https://wanandroid.com/wxarticle/chapters/json
    @GET("wxarticle/chapters/json")
    Call<ResponseBody> getChapters();

  }

Retrofit 대상 을 구축 하 는 가장 간단 하고 원시 적 인 요청 은 addCallAdapterFactory 와 addConverterFactory 를 추가 하지 않 았 습 니 다.
   //   Retrofit  
    Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(ApiServer.baseUrl)
        .build();
  
    //   api    . //  
    ApiServer apiServer = retrofit.create(ApiServer.class);

    // Create a call instance for looking up Retrofit contributors.
  //          
    Call<ResponseBody> chapters = apiServer.getChapters();

    //          
    ResponseBody body = chapters.execute().body();

GsonConverter 변환기 분석 결 과 를 추가 하면 다른 형식의 해석 기 를 사용자 정의 할 수 있 습 니 다.
 Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(ApiServer.baseUrl)
        .addConverterFactory(GsonConverterFactory.create()) //      
        .build();

CallAdapter 요청 어댑터 추가
  Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(ApiServer.baseUrl)
        .addCallAdapterFactory(new MyCallAdapterFactory()) //         
        .addConverterFactory(GsonConverterFactory.create()) //      
        .build();

사용자 정의 CallAdapter 는 DefaultCallAdapter Factory 를 참고 할 수 있 습 니 다.
static class MyCallAdapterFactory extends CallAdapter.Factory {
    @Override public @Nullable CallAdapter<?, ?> get(
            final Type returnType, Annotation[] annotations, Retrofit retrofit) {
      //                            
      if (getRawType(returnType) != Call.class) {
        return null;
      }
      return new CallAdapter<Object, Call<?>>() {
        @Override public Type responseType() {
          return getParameterUpperBound(0, (ParameterizedType) returnType);
        }

        @Override public Call<Object> adapt(Call<Object> call) {
          System.out.println("   ");
          return call;
        }
      };
    }
  }

비교적 간단 한 사용 사례 기타 각종 주 해 는 공식 문 서 를 참고 한다.
2.소스 코드 분석 소스 코드 분석 은 동적 에이전트,어댑터 모델,건설 자 모델 과 관련된다.
1.먼저 Retrofit 의 생 성 과정 을 분석 하고 건축 자 모델 을 통 해 구축 한
  Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(ApiServer.baseUrl)
        .addCallAdapterFactory(new MyCallAdapterFactory()) //         
        .addConverterFactory(GsonConverterFactory.create()) //      
        .build();

1.Retrofit.Builder 대상 을 만 드 는 것 은 플랫폼 문제 와 관련 되 고 여 기 는 Android 플랫폼 네트워크 리 셋 UI 스 레 드 입 니 다.
public Builder() {
      this(Platform.get());
    }
class Platform {
  private static final Platform PLATFORM = findPlatform();

  static Platform get() {
    return PLATFORM;
  }

  private static Platform findPlatform() {
    try {
      Class.forName("android.os.Build");
      if (Build.VERSION.SDK_INT != 0) {
        return new Android();
      }
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform(true);
  }
  
 ......
 
  static final class Android extends Platform {
    Android() {
      super(Build.VERSION.SDK_INT >= 24);
    }

    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }
}


2.여기 baseUrl 에 작은 세부 사항 이 있 습 니 다.baseUrl 은 반드시"/"로 끝 나 는 소스 코드 로 검사 하고 직접 이상 을 던 집 니 다.
 public Builder baseUrl(HttpUrl baseUrl) {
      Objects.requireNonNull(baseUrl, "baseUrl == null");
      List<String> pathSegments = baseUrl.pathSegments();
      if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
        throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
      }
      this.baseUrl = baseUrl;
      return this;
    }

3.다른 addCallAdapter Factory,addConverter Factory 는 모두 해당 하 는 집합 에 추 가 됩 니 다.
 public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
      callAdapterFactories.add(Objects.requireNonNull(factory, "factory == null"));
      return this;
    }
  public Builder addConverterFactory(Converter.Factory factory) {
      converterFactories.add(Objects.requireNonNull(factory, "factory == null"));
      return this;
    }

4.Retrofit 를 조립 하 는 것 은 okhttp 요청 OkHttpClient 를 만 드 는 것 과 관련 되 고 안 드 로 이 드 플랫폼 의 기본 리 셋 은 메 인 스 레 드,callAdapter 와 처리 결 과 를 추가 하 는 변환기 Converter 와 관련 되 며 마지막 으로 이 두 집합 은 모두 읽 기 전용 집합 으로 전환 된다.
 public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();//           okhttp     client
      }
      //      
      Executor callbackExecutor = this.callbackExecutor; 
      if (callbackExecutor == null) {
        //Android        Android      
        callbackExecutor = platform.defaultCallbackExecutor();  
      }

      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories = new ArrayList<>(
          1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());

      // Add the built-in converter factory first. This prevents overriding its behavior but also
      // ensures correct behavior when using converters that consume all types.
      converterFactories.add(new BuiltInConverters());
      converterFactories.addAll(this.converterFactories);
      converterFactories.addAll(platform.defaultConverterFactories());

      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }

2.핵심 인 터 페 이 스 를 분석 하여 구체 적 인 실현 클래스 인 ApiServer apiServer=retrofit.create(ApiServer.class)로 전환한다.동적 에이전트,어댑터 모드 와 관련 하여 인터페이스의 모든 방법 을 ServiceMethod 의 하위 클래스 HttpServiceMethod 로 포장 합 니 다.
 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);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            //        ServiceMethod       HttpServiceMethod     invoke
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }

포장 과정 캐 시 방법 은 매번 반사 소모 성능 을 피한다.
ServiceMethod<?> loadServiceMethod(Method method) {
    ServiceMethod<?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        //          
        result = ServiceMethod.parseAnnotations(this, method);
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

요청 방법 을 해석 하고 처리 하 는 각종 주 해 는 두 단계 로 나 뉘 는데 1.주 해 를 통 해 요청 대상 을 구축한다.
 static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    //            GET POST HEAD  
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);

    Type returnType = method.getGenericReturnType();
    if (Utils.hasUnresolvableType(returnType)) { //           
      throw methodError(method,
          "Method return type must not include a type variable or wildcard: %s", returnType);
    }
    //          void
    if (returnType == void.class) {
      throw methodError(method, "Service methods cannot return void.");
    }

    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }

핵심 방법 RequestFactory 클래스 중
private void parseMethodAnnotation(Annotation annotation) {
      if (annotation instanceof DELETE) {
        parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
      } else if (annotation instanceof GET) {
        parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
      } else if (annotation instanceof HEAD) {
        parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
      } else if (annotation instanceof PATCH) {
        parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
      } else if (annotation instanceof POST) {
        parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
      } else if (annotation instanceof PUT) {
        parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
      } else if (annotation instanceof OPTIONS) {
        parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
      } else if (annotation instanceof HTTP) {
        HTTP http = (HTTP) annotation;
        parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
      } else if (annotation instanceof retrofit2.http.Headers) {
        String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
        if (headersToParse.length == 0) {
          throw methodError(method, "@Headers annotation is empty.");
        }
        headers = parseHeaders(headersToParse);
      } else if (annotation instanceof Multipart) {
        if (isFormEncoded) {
          throw methodError(method, "Only one encoding annotation is allowed.");
        }
        isMultipart = true;
      } else if (annotation instanceof FormUrlEncoded) {
        if (isMultipart) {
          throw methodError(method, "Only one encoding annotation is allowed.");
        }
        isFormEncoded = true;
      }
    }

2.HttpServiceMethod.parseAnnotations(retrofit,method,requestFactory)분석;중요 하지 않 은 코드 를 제거 합 니 다.주로 CallAdapter 와 Converter 컨버터 컨버터 를 수집 하고 마지막 으로 retrofit 류 에 있 는 nextCallAdapter 방법 과 nextResponse Body Converter 방법 을 호출 합 니 다.마지막 으로 new CallAdapted<>(requestFactory,callFactory,response Converter,callAdapter)로 돌아 갑 니 다.
 static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
    boolean continuationWantsResponse = false;
    boolean continuationBodyNullable = false;

    Annotation[] annotations = method.getAnnotations();
    Type adapterType;
    if (isKotlinSuspendFunction) {
     ......
    } else {
      adapterType = method.getGenericReturnType();
    }

    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
      ......

    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);

    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    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);
    }
  }

nextCallAdapter 방법 과 nextResponse Body Converter 방법 은 사용자 정의 CallAdapter 와 Converter 를 사용 할 때 null 을 되 돌려 주 는 것 은 무효 입 니 다.
 public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
    Objects.requireNonNull(returnType, "returnType == null");
    Objects.requireNonNull(annotations, "annotations == null");

    int start = callAdapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
      CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }
    ......
    throw new IllegalArgumentException(builder.toString());
  }

 public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
      @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
    Objects.requireNonNull(type, "type == null");
    Objects.requireNonNull(annotations, "annotations == null");

    int start = converterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = converterFactories.size(); i < count; i++) {
      Converter<ResponseBody, ?> converter =
          converterFactories.get(i).responseBodyConverter(type, annotations, this);
      if (converter != null) {
        //noinspection unchecked
        return (Converter<ResponseBody, T>) converter;
      }
    }
    ......
    throw new IllegalArgumentException(builder.toString());
  }

마지막 으로 new CallAdapted<>(requestFactory,callFactory,responseConverter,callAdapter)를 되 돌려 줍 니 다.대상 CallAdapted 는 HttpServiceMethod 를 계승 합 니 다.
동적 프 록 시 부분 에서 HttpServiceMethod 로 포장 한 후 invoke 를 호출 합 니 다.마지막 call 의 실현 클래스 는 OkHttpCall 입 니 다.adapt 은 callAdapter 의 adapt 방법 을 한 단계 씩 호출 합 니 다.사용자 정의 가 포함 되 어 있 기 때문에 사용자 정의 가 반드시 call 로 돌아 가 야 합 니 다.그렇지 않 으 면 요청 이 중 단 됩 니 다.
 @Override final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }
 static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
    private final CallAdapter<ResponseT, ReturnT> callAdapter;

    CallAdapted(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
        Converter<ResponseBody, ResponseT> responseConverter,
        CallAdapter<ResponseT, ReturnT> callAdapter) {
      super(requestFactory, callFactory, responseConverter);
      this.callAdapter = callAdapter;
    }

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

분석 Call chapters=apiServer.getChapters();apiServer.getChapters()는 OkHttpCall 대상 을 되 돌려 줍 니 다.
요청 을 실행 할 때 chapters.execute()즉,OkHttpCall 의 execute()를 실행 하 는 진정한 네트워크 요청 은 okhttp 프레임 워 크 로 요청 합 니 다.
 @Override public Response<T> execute() throws IOException {
    okhttp3.Call call;

    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;

      if (creationFailure != null) {
        if (creationFailure instanceof IOException) {
          throw (IOException) creationFailure;
        } else if (creationFailure instanceof RuntimeException) {
          throw (RuntimeException) creationFailure;
        } else {
          throw (Error) creationFailure;
        }
      }

      call = rawCall;
      if (call == null) {
        try {
          call = rawCall = createRawCall();
        } catch (IOException | RuntimeException | Error e) {
          throwIfFatal(e); //  Do not assign a fatal error to creationFailure.
          creationFailure = e;
          throw e;
        }
      }
    }

    if (canceled) {
      call.cancel();
    }

    return parseResponse(call.execute());
  }


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

    // Remove the body's source (the only stateful object) so we can pass the response along.
    rawResponse = rawResponse.newBuilder()
        .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
        .build();

    int code = rawResponse.code();
    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();
      }
    }

    if (code == 204 || code == 205) {
      rawBody.close();
      return Response.success(null, rawResponse);
    }

    ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
    try {
     //      
      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();
      throw e;
    }
  }

이로써 주류 프로 세 스 완성 핵심 모듈 은 동적 에이전트 에서

좋은 웹페이지 즐겨찾기