目录
一,Retrofit的基本使用
1.定义api接口
2.创建Retrofit实例
3.获取api接口实例发起请求
二,静态代理和动态代理
1,静态代理
2,动态代理
三,动态代理获取Api接口实例
四,解析接口方法注解,生成请求方法
五,代理发起网络请求
六,Retrofit如何实现线程切换?
一,Retrofit的基本使用
1.定义api接口
public interface ApiService {
// GET 请求示例
@GET("users/{id}")
Call<User> getUser(@Path("id") int userId);
// POST 请求示例
@POST("users")
Call<User> createUser(@Body User user);
// 带查询参数的 GET 请求示例
@GET("users")
Call<List<User>> getUsers(@Query("page") int page, @Query("size") int size);
}
2.创建Retrofit实例
public class ApiClient {
private static final String BASE_URL = "https://api.github.com/";
private static Retrofit retrofit;
public static Retrofit getClient() {
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create()) // 使用 Gson 解析器
.build();
}
return retrofit;
}
}
3.获取api接口实例发起请求
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 获取 apiService 实例
ApiService apiService = ApiClient.getClient().create(ApiService.class);
// 创建请求
Call<User> call = apiService.getUser("octocat");
// 异步请求
call.enqueue(new Callback<User>() {
@Override
public void onResponse(Call<User> call, Response<User> response) {
if (response.isSuccessful()) {
// 请求成功,处理数据
User user = response.body();
Log.d("Retrofit", "User: " + user.getName());
} else {
// 请求失败
Log.e("Retrofit", "Request failed");
}
}
@Override
public void onFailure(Call<User> call, Throwable t) {
// 请求失败
Log.e("Retrofit", "Request error", t);
}
});
}
}
从Retrofit的使用入手,Retrofit的核心在于:
- 通过动态代理获取apiService实例,对api请求方法进行拓展。
- 在代理对象的invoke方法中对接口方法进行解析,解析注解,参数,参数注解,返回类型等。
- 代理用于发送请求的Call对象执行网络请求,并拦截响应。
- 底层使用Handler机制切换到主线程,并将响应结果返回。
二,静态代理和动态代理
首先,我们先了解一下代理模式:
代理模式:通过代理对象来代替真实对象的访问,从而在不修改原对象的情况下,对原对象的方法进行拓展
代理模式一般包含这几个元素:
- 委托类(被代理的类)
- 接口(委托类实现的方法)
- 代理类
1,静态代理
静态代理分为以下几个步骤:
- 创建一个接口,定义方法
- 创建一个委托类实现接口
- 创建一个代理类,持有委托类的引用,实现与委托类相同的接口
(1)创建接口
/*
委托接口
*/
interface ClientInterface {
fun call()
}
(2)创建委托类实现接口
/*
委托类
*/
class Client : ClientInterface {
override fun call() {
println("Client Call")
}
}
(3)创建代理类,实现与委托类相同的接口
/*
代理类
*/
class Proxy : ClientInterface {
var client : Client? = null
fun setInstance(client: Client){
this.client = client;
}
override fun call() {
println("proxy pre call")
client?.call()
println("proxy aft call")
}
}
这样我们就可以通过使用代理类的call方法,从而对委托类的方法进行拓展;
2,动态代理
动态代理与静态代理的区别就是:动态代理的代理对象由Java中的Proxy.newProxyInstance()在运行时动态生成。
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
这个方法需要的三个参数为:
- loader:委托类的类加载器
- interfaces:委托类实现的接口
- h:一个实现了InvocationHandler的类,在这个类的invoke方法中对委托类的方法进行拓展
(1)同样创建委托类和接口
/*
委托类,也就是代理对象
*/
class Client : ClientInterface {
override fun call() {
println("client call")
}
}
/*
委托接口,代理类实现的接口
*/
interface ClientInterface {
fun call()
fun call1()
}
(2)创建实现InvocationHandler的类
/*
实现了InvocationHandler的类
*/
class CallInvocationHandler(private var target: Any) : InvocationHandler {
//代理类调用的方法会被转发到这里运行
override fun invoke(proxy: Any, method: Method, args: Array<out Any>?): Any? {
println("before client: ${args.toString()} call: ${method.name}")
return method.invoke(target, args)
}
}
(3)使用Proxy.newProxyInstance()生成代理对象
class Application3 {
fun main(){
val client : ClientInterface = Client()
val proxy = Proxy.newProxyInstance(
client::class.java.classLoader, //代理对象的类加载器,用于加载代理对象
arrayOf(client::class.java), //代理对象实现的接口,也就是代理对象要进行的业务
CallInvocationHandler(client) //实现了 InvocationHandler 接口的对象,通过代理类调用代理对象的方法时,就会转发到invoke方法中被调用
) as Client
proxy.call();
}
}
动态代理(JDK动态代理)只能代理实现了接口的类,所以与其说代理类代理了委托类,不如说它是代理了接口
三,动态代理获取Api接口实例
当我们明白了动态代理之后,我们再来看Retrofit的create方法:
private val apiService : ApiService = RetrofitClient.getInstance().create(ApiService::class.java)
public <T> T create(final Class<T> service) {
validateServiceInterface(service);
//动态代理,获取ApiService的代理对象
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 {
// object类中的方法直接调用
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
//检查是否含有默认实现,如果有直接按默认实现调用,
//没有则进入loadServiceMethod方法
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;
}
可见Retrofit通过create方法创建了一个ApiService的代理类。通过ApiService代理类调用请求方法时,就会被转发到InvocationHandler的invoke方法中进行解析(loadServiceMethod)和调用(invoke)。
四,解析接口方法注解,生成请求方法
接着,Retrofit通过ServiceMethod类对方法及方法注解进行解析:
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
//构建请求工厂
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
...
//封装,形成完整的可执行的请求
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
abstract @Nullable T invoke(Object[] args);
}
ServiceMethod是一个抽象类,实现类为HttpServiceMethod。
ServiceMethod首先构建了一个RequestFactory,RequestFactory中封装了从接口方法解析到的信息,包括:
- 请求方法(GET, POST等)
- baseUrl和请求的相对路径
- 请求头,请求参数,请求体等
final class RequestFactory {
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
private final Method method; //接口方法
private final HttpUrl baseUrl; //baseUrl
final String httpMethod; //请求方法 get,post等
private final @Nullable String relativeUrl; //请求的相对路径
private final @Nullable Headers headers; //请求头
private final @Nullable MediaType contentType; //请求体MIME类型
private final boolean hasBody; //是否包含请求体
private final boolean isFormEncoded; //是否是表单编码请求
private final boolean isMultipart; //是否是多部分请求
private final ParameterHandler<?>[] parameterHandlers; //参数处理数组,根据参数注解决定如何处理参数
final boolean isKotlinSuspendFunction; //是否为kotlin挂起函数
}
接着在HttpServiceMethod中,使用适配器,格式转换器,结合RequestFactory将请求信息封装为可执行的完整的请求
核心代码:
static <T> HttpServiceMethod<T> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
CallAdapter<T, ?> callAdapter = createCallAdapter(retrofit, method);
Type responseType = callAdapter.responseType();
Converter<ResponseBody, T> responseConverter = createResponseConverter(retrofit, method, responseType);
return new HttpServiceMethod<>(requestFactory, callAdapter, responseConverter);
}
核心组件:
-
callAdapter适配器:将底层的call对象适配为用户接口返回的类型(Call<T>, Flow<T>, LiveData<T>等);
-
converter格式转化器:例如转化Json格式数据
-
RequestFactory:之前封装好的请求信息
五,代理发起网络请求
在请求构建完毕后,就会调用invoke方法,具体调用的是HttpServiceMethod类中的invoke方法
invoke方法中又返回了adapt方法的调用,adapt方法的具体实现交给三个子类:
-
CallAdapted<ResponseT, ReturnT>:适配返回类型为标准Java类型,如Call<T>,或者RxJava的Single<T>, Observer<T>类型。
-
SuspendForResponse<ResponseT>:适配 Kotlin 协程场景,当接口方法的返回类型为 suspend fun 且需要返回一个 Respond<T>(完整的 HTTP 响应对象)时使用。
-
SuspendForBody<ResponseT>:适配 Kotlin 协程场景,当接口方法的返回类型为 suspend fun 且只需要返回响应体对象 T(不需要完整的 HTTP 响应对象)时使用。
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
}
static final class SuspendForResponse<ResponseT> extends HttpServiceMethod<ResponseT, Object> {
}
static final class SuspendForBody<ResponseT> extends HttpServiceMethod<ResponseT, Object> {
}
一般情况,使用的都是CallAdapted子类,CallAdapted子类中的adapt方法返回callAdapter的adapt方法调用:
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<T>,对应的callAdapter由Retrofit默认添加的DefaultCallAdapterFactory生成:
@Override
public @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
if (!(returnType instanceof ParameterizedType)) {
throw new IllegalArgumentException(
"Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
}
final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);
final Executor executor =
Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
? null
: callbackExecutor;
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);
}
};
}
adapt方法最后返回ExecutorCallbackCall对象,所以调用ApiService代理类的请求方法,最终返回的是call对象为ExecutorCallbackCall对象。
或者说是使用了代理模式,将call的功能代理到了ExecutorCallbackCall中,当我们调用call的异步方法enquque时,最终调用到的是ExecutorCallbackCall的enquque方法。
在ExecutorCallbackCall的enquque方法调用了原call对象的异步请求方法,并拦截了onResponse 和 onFailure 回调,切换到指定的线程(通常是主线程),也就是Retrofit中的onResponse 和 onFailure 回调最终是在主线程中获取到的。
至此,Retrofit的整个流程就结束了。
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate; //被代理的call对象
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
//调用原call对象的异步请求方法
delegate.enqueue(
new Callback<T>() {
//拦截底层的 onResponse 和 onFailure 回调,切换到指定的线程(通常是主线程)。
@Override
public void onResponse(Call<T> call, final Response<T> response) {
//这里切换到主线程
callbackExecutor.execute(
() -> {
if (delegate.isCanceled()) {
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
});
}
@Override
public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
}
});
}
@Override
public boolean isExecuted() {
return delegate.isExecuted();
}
@Override
public Response<T> execute() throws IOException {
return delegate.execute();
}
@Override
public void cancel() {
delegate.cancel();
}
@Override
public boolean isCanceled() {
return delegate.isCanceled();
}
@SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.
@Override
public Call<T> clone() {
return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());
}
@Override
public Request request() {
return delegate.request();
}
@Override
public Timeout timeout() {
return delegate.timeout();
}
}
六,Retrofit如何实现线程切换?
ExecutorCallbackCall代理类发起请求后,在响应回调中,通过callbackExecutor.execute切换到主线程。
这里的callbackExecutor是Retrofit在构建时配置的:
public Retrofit build() {
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
}
在Retrofit的Platform中,Android平台默认返回一个MainThreadExecutor,在MainThreadExecutor的execute方法中,线程通过Hanlder进行切换。
static class Android extends Platform {
@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进行线程切换
handler.post(r);
}
}
}