build.gradle

dependencies {

//retrofit + gson + rxjava

implementation 'com.squareup.retrofit2:retrofit:2.9.0'

implementation 'com.squareup.retrofit2:converter-gson:2.5.0'

implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0'

}

interface ApiService {

@GET("getUserData")

fun getUserData1(): Call

}

fun main1() {

val retrofit = Retrofit.Builder()

.baseUrl("http://mockapi.eolinker.com/9IiwI82f58c23411240ed608ceca204b2f185014507cbe3/")

.build()

val service = retrofit.create(ApiService::class.java)

val call: Call = service.getUserData1()

call.enqueue(object : Callback {

override fun onResponse(call: Call, response: Response) {

val userBean = response.body()?.string()

println("userBean: $userBean")

}

override fun onFailure(call: Call, t: Throwable) {

println("onFailure: $t")

}

})

}

Retrofit 是建立在 OkHttp 之上的一个网络请求封装库,内部依靠 okhttp 来完成实际网络请求。Retrofit 在使用上很简洁, API 通过 interface 来声明。我只需要通过 interface 来声明 API路径、请求方式、请求参数、返回值类型等各个配置项。

可以看到,getUserData() 方法的请求结果是一个 json 格式的字符串,其返回值类型被定义为 Call , 此处的 ResponseBody 即 okHttp3.ResponseBody ,是 okhttp 提供的对网络请求结果的包装类,Call 即 retrofit2.Call ,是 Retrofit 对 okhttp3.Call 做的一层包装,OkHttp在实际发起请求的时候使用的回调是 okhttp3.Call ,回调内部会中转调用 retrofit2.Call,以便将请求结果转交给外部。

1、converter-gson

API 返回值 Json 转换 :

interface ApiService {

@GET("getUserData")

fun getUserData2(): Call

}

data class UserBean(val status: Int, val msg: String, val data: Data)

data class Data(val userName: String, val userAge: Long)

fun main2() {

val retrofit = Retrofit.Builder()

.baseUrl("http://mockapi.eolinker.com/9IiwI82f58c23411240ed608ceca204b2f185014507cbe3/")

.addConverterFactory(GsonConverterFactory.create())

.build()

val service = retrofit.create(ApiService::class.java)

val call: Call = service.getUserData2()

call.enqueue(object : Callback {

override fun onResponse(call: Call, response: Response) {

val userBean = response.body()

println("userBean: $userBean")

}

override fun onFailure(call: Call, t: Throwable) {

println("onFailure: $t")

}

})

}

2、adapter-rxjava2

adapter-rxjava2 转换返回值为被观察者

interface ApiService {

@GET("getUserData")

fun getUserData3(): Observable

}

data class UserBean(val status: Int, val msg: String, val data: Data)

data class Data(val userName: String, val userAge: Long)

fun main3() {

val retrofit = Retrofit.Builder()

.baseUrl("http://mockapi.eolinker.com/9IiwI82f58c23411240ed608ceca204b2f185014507cbe3/")

.addConverterFactory(GsonConverterFactory.create())

.addCallAdapterFactory(RxJava2CallAdapterFactory.create())

.build()

val service = retrofit.create(ApiService::class.java)

val call: Observable = service.getUserData3()

call.subscribe({ user ->

println("userBean: $user")

}, { t ->

println("onFailure: $t")

})

}

一、Retrofit请求过程 

1、Retrofit.create()

@SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.

public T create(final Class 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);

}

});

}

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;

}

 

2、ServiceMethod 

abstract class ServiceMethod {

static ServiceMethod parseAnnotations(Retrofit retrofit, Method method) {

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);

}

if (returnType == void.class) {

throw methodError(method, "Service methods cannot return void.");

}

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

}

abstract @Nullable T invoke(Object[] args);

}

 3、HttpServiceMethod

abstract class HttpServiceMethod extends ServiceMethod {

static HttpServiceMethod 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) {

Type[] parameterTypes = method.getGenericParameterTypes();

Type responseType =

Utils.getParameterLowerBound(

0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]);

if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {

// Unwrap the actual body type from Response.

responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);

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

}

adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);

annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);

} else {

adapterType = method.getGenericReturnType();

}

CallAdapter callAdapter =

createCallAdapter(retrofit, method, adapterType, annotations);

Type responseType = callAdapter.responseType();

if (responseType == okhttp3.Response.class) {

throw methodError(

method,

"'"

+ getRawType(responseType).getName()

+ "' is not a valid response body type. Did you mean ResponseBody?");

}

if (responseType == Response.class) {

throw methodError(method, "Response must include generic type (e.g., Response)");

}

// TODO support Unit for Kotlin?

if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {

throw methodError(method, "HEAD method must use Void as response type.");

}

Converter 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)

new SuspendForResponse<>(

requestFactory,

callFactory,

responseConverter,

(CallAdapter>) callAdapter);

} else {

//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.

return (HttpServiceMethod)

new SuspendForBody<>(

requestFactory,

callFactory,

responseConverter,

(CallAdapter>) callAdapter,

continuationBodyNullable);

}

}

@Override

final @Nullable ReturnT invoke(Object[] args) {

Call call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);

return adapt(call, args);

}

}

 4、OkHttpCall

OkHttpCall 是实际发起 okHttp 请求的地方。当我们调用 fun getUserData(): Call 方法时,返回的 Call 对象实际上是 OkHttp 类型。

final class OkHttpCall implements Call {

private final RequestFactory requestFactory;

private final Object[] args;

private final okhttp3.Call.Factory callFactory;

private final Converter responseConverter;

private volatile boolean canceled;

@GuardedBy("this")

private @Nullable okhttp3.Call rawCall;

@GuardedBy("this") // Either a RuntimeException, non-fatal Error, or IOException.

private @Nullable Throwable creationFailure;

@GuardedBy("this")

private boolean executed;

OkHttpCall(

RequestFactory requestFactory,

Object[] args,

okhttp3.Call.Factory callFactory,

Converter responseConverter) {

this.requestFactory = requestFactory;

this.args = args;

this.callFactory = callFactory;

this.responseConverter = responseConverter;

}

@SuppressWarnings("CloneDoesntCallSuperClone") // We are a final type & this saves clearing state.

@Override

public OkHttpCall clone() {

return new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);

}

@Override

public synchronized Request request() {

try {

return getRawCall().request();

} catch (IOException e) {

throw new RuntimeException("Unable to create request.", e);

}

}

@Override

public synchronized Timeout timeout() {

try {

return getRawCall().timeout();

} catch (IOException e) {

throw new RuntimeException("Unable to create call.", e);

}

}

/**

* Returns the raw call, initializing it if necessary. Throws if initializing the raw call throws,

* or has thrown in previous attempts to create it.

*/

@GuardedBy("this")

private okhttp3.Call getRawCall() throws IOException {

okhttp3.Call call = rawCall;

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 {

return rawCall = createRawCall();

} catch (RuntimeException | Error | IOException e) {

throwIfFatal(e); // Do not assign a fatal error to creationFailure.

creationFailure = e;

throw e;

}

}

@Override

public void enqueue(final Callback 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 {

call = rawCall = createRawCall();

} catch (Throwable t) {

throwIfFatal(t);

failure = creationFailure = t;

}

}

}

if (failure != null) {

callback.onFailure(this, failure);

return;

}

if (canceled) {

call.cancel();

}

call.enqueue(

new okhttp3.Callback() {

@Override

public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {

Response response;

try {

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

}

}

});

}

@Override

public synchronized boolean isExecuted() {

return executed;

}

@Override

public Response execute() throws IOException {

okhttp3.Call call;

synchronized (this) {

if (executed) throw new IllegalStateException("Already executed.");

executed = true;

call = getRawCall();

}

if (canceled) {

call.cancel();

}

return parseResponse(call.execute());

}

}

 5、RequestFactory

final class RequestFactory {

static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {

return new Builder(retrofit, method).build();

}

private final Method method;

private final HttpUrl baseUrl;

final String httpMethod;

private final @Nullable String relativeUrl;

private final @Nullable Headers headers;

private final @Nullable MediaType contentType;

private final boolean hasBody;

private final boolean isFormEncoded;

private final boolean isMultipart;

private final ParameterHandler[] parameterHandlers;

final boolean isKotlinSuspendFunction;

RequestFactory(Builder builder) {

method = builder.method;

baseUrl = builder.retrofit.baseUrl;

httpMethod = builder.httpMethod;

relativeUrl = builder.relativeUrl;

headers = builder.headers;

contentType = builder.contentType;

hasBody = builder.hasBody;

isFormEncoded = builder.isFormEncoded;

isMultipart = builder.isMultipart;

parameterHandlers = builder.parameterHandlers;

isKotlinSuspendFunction = builder.isKotlinSuspendFunction;

}

okhttp3.Request create(Object[] args) throws IOException {

@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.

ParameterHandler[] handlers = (ParameterHandler[]) parameterHandlers;

int argumentCount = args.length;

if (argumentCount != handlers.length) {

throw new IllegalArgumentException(

"Argument count ("

+ argumentCount

+ ") doesn't match expected count ("

+ handlers.length

+ ")");

}

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 argumentList = new ArrayList<>(argumentCount);

for (int p = 0; p < argumentCount; p++) {

argumentList.add(args[p]);

handlers[p].apply(requestBuilder, args[p]);

}

return requestBuilder.get().tag(Invocation.class, new Invocation(method, argumentList)).build();

}

/**

* Inspects the annotations on an interface method to construct a reusable service method. This

* requires potentially-expensive reflection so it is best to build each service method only once

* and reuse it. Builders cannot be reused.

*/

static final class Builder {

// Upper and lower characters, digits, underscores, and hyphens, starting with a character.

private static final String PARAM = "[a-zA-Z][a-zA-Z0-9_-]*";

private static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{(" + PARAM + ")\\}");

private static final Pattern PARAM_NAME_REGEX = Pattern.compile(PARAM);

final Retrofit retrofit;

final Method method;

final Annotation[] methodAnnotations;

final Annotation[][] parameterAnnotationsArray;

final Type[] parameterTypes;

boolean gotField;

boolean gotPart;

boolean gotBody;

boolean gotPath;

boolean gotQuery;

boolean gotQueryName;

boolean gotQueryMap;

boolean gotUrl;

@Nullable String httpMethod;

boolean hasBody;

boolean isFormEncoded;

boolean isMultipart;

@Nullable String relativeUrl;

@Nullable Headers headers;

@Nullable MediaType contentType;

@Nullable Set relativeUrlParamNames;

@Nullable ParameterHandler[] parameterHandlers;

boolean isKotlinSuspendFunction;

Builder(Retrofit retrofit, Method method) {

this.retrofit = retrofit;

this.method = method;

this.methodAnnotations = method.getAnnotations();

this.parameterTypes = method.getGenericParameterTypes();

this.parameterAnnotationsArray = method.getParameterAnnotations();

}

RequestFactory build() {

for (Annotation annotation : methodAnnotations) {

parseMethodAnnotation(annotation);

}

if (httpMethod == null) {

throw methodError(method, "HTTP method annotation is required (e.g., @GET, @POST, etc.).");

}

if (!hasBody) {

if (isMultipart) {

throw methodError(

method,

"Multipart can only be specified on HTTP methods with request body (e.g., @POST).");

}

if (isFormEncoded) {

throw methodError(

method,

"FormUrlEncoded can only be specified on HTTP methods with "

+ "request body (e.g., @POST).");

}

}

int parameterCount = parameterAnnotationsArray.length;

parameterHandlers = new ParameterHandler[parameterCount];

for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {

parameterHandlers[p] =

parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);

}

if (relativeUrl == null && !gotUrl) {

throw methodError(method, "Missing either @%s URL or @Url parameter.", httpMethod);

}

if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {

throw methodError(method, "Non-body HTTP method cannot contain @Body.");

}

if (isFormEncoded && !gotField) {

throw methodError(method, "Form-encoded method must contain at least one @Field.");

}

if (isMultipart && !gotPart) {

throw methodError(method, "Multipart method must contain at least one @Part.");

}

return new RequestFactory(this);

}

}

 

参考:

https://github.com/leavesCZY/AndroidGuide/blob/master/%E4%B8%BB%E6%B5%81%E5%BC%80%E6%BA%90%E5%BA%93%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90%EF%BC%887%EF%BC%89Retrofit%20%E6%BA%90%E7%A0%81%E8%AF%A6%E8%A7%A3.md

推荐文章

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。

发表评论

返回顶部暗黑模式