Retrofit源码解析(二)

Retrofit源码解析(一)
Retrofit源码解析(三)

上一篇中大致对比了okhttp和retrofit发送请求的大致流程,了解okhttp的工作流程对掌握retrofit是非常重要的。本篇继续讲解retrofit的内部构成。retrofit使用Builder模式完成构建,通过Builder模式开发者可以配置常用的GsonConvertFactory完成json数据实例化,也可以添加RxJava2CallAdapterFactory进行自定义请求,最终这些额外的配置都被保存在Retrofit的实例当中。下面先来看Retrofit的属性都有哪些:

public final class Retrofit {
  private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();

  final okhttp3.Call.Factory callFactory;
  final HttpUrl baseUrl;
  final List<Converter.Factory> converterFactories;
  final List<CallAdapter.Factory> callAdapterFactories;
  final @Nullable Executor callbackExecutor;
  	···
  }

serviceMethodCache

serviceMethodCache是一个存储ServiceMethod的map。ServiceMethod是一个非常重要的类,我们在接口中定义的每一个请求方法最终都会在运行时被解析,方法注解中的所有信息都会被保存在一个ServiceMethod对象中。当方法被调用时,retrofit通过动态代理拿到运行时Method对象,根据Method对象构建一个ServiceMethod对象,并调用ServiceMethod的invoke方法完成最终的请求。

callFactory

callFactory是Okhttp中定义的接口,并不是retrofit定义的。他的作用就是创建网络请求的真正的Call对象。通过引用接口,开发者就可以注入自己的默认实现,达到多态的效果。他有一个默认的实现类大家都不会陌生:OkHttpClient。上一篇中我们说过retrofit是通过okhttp完成的网络请求,实际的体现就是这里。

package okhttp3;

public interface Call extends Cloneable {
 
 	···

  interface Factory {
		Call newCall(Request request);
	}
}


public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
   ···
}

baseUrl

这个类比较简单,就是用来保存baseUrl,不再多说。

converterFactories

Converter.Factory是retrofit中定义的类。我们知道在okhttp的回调方法中,最终的返回值是一个固定的类型Response。通过response.body()方法可以获取到ResponseBody对象进而通过responseBody.string()方法获取body的实际内容,这些类型都是固定的需要我们自己对返回结果进行手动解析。

但是在retrofit中,在数据请求成功回调后,retrofit会在converterFactories列表中根据接口中方法的返回值Call<T>的泛型T,选择一个合适的转化器工厂,自动进行类型转化.

package retrofit2;

public interface Converter<F, T> {

	@Nullable
  	T convert(F value) throws IOException;
	
	
	abstract class Factory {
	
		 public @Nullable Converter<ResponseBody, ?> responseBodyConverter(
	        Type type, Annotation[] annotations, Retrofit retrofit) {
	      return null;
	    }
	    
		···
	}
}

Converter.Factory有一个默认的实现类BuiltInConverters,在创建retrofit的时候会永远把BuiltInConverters放在converterFactories列表的第一个。BuiltInConverters是 retrofit 提供的默认数据转化器工厂,他的转化只是将ResponseBody直接缓存返回,并没有其他额外的工作。所以如果在接口中定义的方法的返回值是Call<ResponseBody>的时候,这时候retrofit就会使用BuiltInConverters进行数据转化。

如果我们又向retrofit中添加了GsonConvertFactory,此时接口中方法的返回值就可以写成这样Call<User>,这时泛型不再是ResponseBody而是User,retrofit就会选择使用GsonConvertFactory进行数据转化。然后在回调中我们就可以直接获取到User对象了。

callAdapterFactories

这里retrofit使用适配器模式对最原始的okhttp中的Call对象进行一层层的装饰,每一层的包装都可以完成一些自定义的对Okhttp的Call的操作,比例:线程切换。在构建ServiceMethod的时候,retrofit会根据接口中定义方法的返回值类型去callAdapterFactories中查找符合要求的adapter工厂。

CallAdapter.Factory也是retrofit提供的一个抽象的工厂类。

package retrofit2;

public interface CallAdapter<R, T> {
	···
	abstract class Factory {
			···
   }
}

DefaultCallAdapterFactory是该类的默认实现,在构建retrofit时会自动添加到callAdapterFactories列表中。DefaultCallAdapterFactory只会处理接口中方法返回值为Call<T>的类型。所以在默认情况下我们必须将接口中方法的返回值定义为Call<T>类型,否则会抛出异常。

如果我们又为retrofit添加了RxJava2CallAdapterFactory,那么此时接口中定义的方法就可以返回Observable<T>了,然后我们就可以使用RXJava的方式进行请求。但是此时callAdapterFactories列表中只有DefaultCallAdapterFactory和RxJava2CallAdapterFactory两个工厂,也就是说现在接口中方法可以接受的返回值有Call<T>和Observable<T>两种类型。如果你写一个String类型,那么同样会抛出异常。

callbackExecutor

就是有个普通的线程池,他的默认实现是一个通过Handler在主线程执行的类,retrofit默认的线程调度就是通过这个线程池。

package retrofit2;

class Platform {
	static final class MainThreadExecutor implements Executor {
	      private final Handler handler = new Handler(Looper.getMainLooper());
	
	      @Override
	      public void execute(Runnable r) {
	        handler.post(r);
	      }
	}
}

总结

可以看到retrofit的设计处处都透露着设计模式和代码的基本原则。在retrofit中引用了三种抽象的工厂,开发人员可以注入自己的工厂实现。用装饰器模式对okhttp的Call进行自定义的处理达到线程切换的效果、通过动态代理执行网络请求等等。本篇从整体介绍了retrofit内部成员的职责,下一篇中将开始系统的讲解retrofit是如何发送网络请求到数据解析的整个流程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Retrofit是一个非常流行的网络请求库,但是在实际开发中,我们经常需要对其进行次封装,以便于更好地满足我们的业务需求。下面是一个简单的Retrofit次封装示例: 首先,我们需要创建一个RetrofitClient类用于创建和管理Retrofit对象。 ```java public class RetrofitClient { private static final String BASE_URL = "https://api.example.com/"; private static RetrofitClient instance; private Retrofit retrofit; private RetrofitClient() { OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); httpClient.addInterceptor(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request original = chain.request(); Request request = original.newBuilder() .header("Accept", "application/json") .method(original.method(), original.body()) .build(); return chain.proceed(request); } }); retrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .client(httpClient.build()) .build(); } public static synchronized RetrofitClient getInstance() { if (instance == null) { instance = new RetrofitClient(); } return instance; } public ApiService getApiService() { return retrofit.create(ApiService.class); } } ``` 上述代码中,我们创建了一个RetrofitClient单例类,并在构造方法中创建了一个OkHttpClient对象,并添加了一个Interceptor拦截器。这个拦截器用于添加请求头,以便于在请求数据时能够正确地解析json格式的数据。我们还创建了一个Retrofit对象,并指定了其基础URL、解析工厂和OkHttpClient对象。 接下来,我们需要创建一个ApiService接口,用于定义我们的网络请求接口。 ```java public interface ApiService { @GET("users") Call<List<User>> getUsers(); } ``` 上述代码中,我们定义了一个getUsers方法,用于获取用户列表。我们使用了Retrofit的注解方式,指定了请求方式和请求路径。 最后,我们需要创建一个DataManager类,用于封装我们的网络请求操作。 ```java public class DataManager { private ApiService apiService; public DataManager() { apiService = RetrofitClient.getInstance().getApiService(); } public void getUsers(final OnDataLoadedListener listener) { Call<List<User>> call = apiService.getUsers(); call.enqueue(new Callback<List<User>>() { @Override public void onResponse(Call<List<User>> call, Response<List<User>> response) { if (response.isSuccessful()) { List<User> users = response.body(); if (listener != null) { listener.onDataLoaded(users); } } else { if (listener != null) { listener.onDataLoadFailed(response.message()); } } } @Override public void onFailure(Call<List<User>> call, Throwable t) { if (listener != null) { listener.onDataLoadFailed(t.getMessage()); } } }); } } ``` 上述代码中,我们创建了一个DataManager类,并在构造方法中获取ApiService对象。我们还定义了一个getUsers方法,用于请求用户列表数据。我们使用了Retrofit的异步请求方式,并在回调函数中处理请求结果。如果请求成功,我们会将获取到的数据通过OnDataLoadedListener回调接口返回给调用方。如果请求失败,我们会将失败信息通过OnDataLoadedListener回调接口返回给调用方。 这样,我们就完成了一个简单的Retrofit次封装。在实际开发中,我们可以根据业务需求对其进行更加复杂的封装。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值