Retrofit 학습 노트-간단 한 사용 과 소스 분석 은 okhttp 와 관련 이 없습니다.
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;
}
}
이로써 주류 프로 세 스 완성 핵심 모듈 은 동적 에이전트 에서
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.