Retrofit
不算是一个网络库,它应该算是封装了 okhttp
,retrofit的最大特点就是解耦,要解耦就需要大量的设计模式,然后为我们提供了一个友好的接口的一个工具库吧。
1、创建Retrofit对象:
builder 模式,外观模式(门面模式)
外观模式具有高内聚、低耦合的特性,对外提供简单统一的接口,隐蔽了子系统具体的实现、隔离变化。
在封装某些特定功能时,比如下载module,外观模式是一种很好的设计规范。即下载module与其他module通信时通过DownloadManager对象进行。Retrofit是整个库的一个入口类,Retrofit库的使用基本都是围绕着这个类。
1 Retrofit retrofit = new Retrofit.Builder() 2 .baseUrl("https://api.github.com/") 3 .build();
2、定义api
public interface StudentApi { /** * 学生列表 for age */ @POST("/student/studentList") Observable<List<Student>> selectStudentListForAge(@Field("age") int age); }
获取 API 实例:通过动态代理模式:使用动态代理,因为对接口的所有方法的调用都会集中转发到 InvocationHandler#invoke
函数中,我们可以集中进行处理,更方便了。
// 在请求,初始化StudentApi StudentApi mStudentApi = retrofit.create(StudentApi.class);
调用create()方法,通过 Proxy 类静态函数生成代理对象StudentApi并返回:
Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h);
loader
表示类加载器interfaces
表示委托类的接口,生成代理类时需要实现这些接口h
是InvocationHandler
实现类对象,负责连接代理类和委托类的中间类
关于动态代理的详细介绍,可以查看 codeKK 公共技术点之 Java 动态代理这篇文章。
1 // 调用其方法时,调用了Retrofit的动态代理的InvocationHandler对象MethodHandler对象 2 mStudentApi.selectStudentListForAge(18)....;
执行该方法后,调用了InvocationHandler对象的invoke方法。
在invoke方法上,处理并返回一个http请求对象,在此,还可以做些有用的操作,例如统计执行时间、进行初始化和清理、对接口调用进行检查等。
1 // 调用代理对象的每个函数实际最终都是调用了InvocationHandler的invoke函数 2 @Override 3 public Object invoke(Object proxy, Method method, Object[] args)
proxy
通过 Proxy.newProxyInstance() 生成的代理类对象。method
表示代理对象被调用的函数。args
表示代理对象被调用的函数的参数。
1、当执行subscribe的时候,整个http请求执行。
2、调用
mStudentApi.selectStudentListForAge(18)
返回对象的execute()
或enqueue(Callback<T> callback)
方法,就能发送一个Http请求了:
1 mStudentApi.selectStudentListForAge(18) 2 .observeOn(AndroidSchedulers.mainThread()) 3 .subscribe(new Subscriber<List<Student>>() { 4 @Override 5 public void onCompleted() { 6 7 } 8 9 @Override 10 public void onError(Throwable e) { 11 12 } 13 14 @Override 15 public void onNext(List<Student> studentList) { 16 17 } 18 }));
熟练使用annotation、reflect,造一个retrofit雏形。
定义post、get、field等:
1 import java.lang.annotation.Documented; 2 import java.lang.annotation.Retention; 3 import java.lang.annotation.Target; 4 import static java.lang.annotation.ElementType.METHOD; 5 import static java.lang.annotation.RetentionPolicy.RUNTIME; 6 7 @Documented 8 @Target(METHOD) 9 @Retention(RUNTIME) 10 public @interface POST { 11 String value() default ""; 12 13 boolean requestSync() default false; 14 }
POST
1 import java.lang.annotation.Documented; 2 import java.lang.annotation.Retention; 3 import java.lang.annotation.Target; 4 import static java.lang.annotation.ElementType.METHOD; 5 import static java.lang.annotation.RetentionPolicy.RUNTIME; 6 7 @Documented 8 @Target(METHOD) 9 @Retention(RUNTIME) 10 public @interface GET { 11 String value() default ""; 12 }
GET
1 import java.lang.annotation.Documented; 2 import java.lang.annotation.Retention; 3 import java.lang.annotation.Target; 4 import static java.lang.annotation.ElementType.PARAMETER; 5 import static java.lang.annotation.RetentionPolicy.RUNTIME; 6 7 @Documented 8 @Target(PARAMETER) 9 @Retention(RUNTIME) 10 public @interface Field { 11 String value(); 12 13 boolean encoded() default false; 14 }
Field
创建BaseRetrofit对象,作为基类,其子类继承并重写createApi方法,在方法中,创建并配置retrofit对象。
1 import java.util.Map; 2 import java.util.concurrent.ConcurrentHashMap; 3 4 public abstract class BaseRetrofit { 5 6 // http请求 7 SimpleRepository repository; 8 9 public <T> T create(Class<T> clazz) { 10 // 可做缓存对象操作 11 T t = createApi(clazz); 12 return t; 13 } 14 15 protected abstract <T> T createApi(Class<T> clazz); 16 17 protected RepositoryProxy.Builder getProxyBuilder(){ 18 return new RepositoryProxy.Builder(){ 19 @Override 20 public RepositoryProxy build() { 21 RepositoryProxy proxy = super.build(); 22 23 setRepository(proxy.getRepository()); 24 25 return proxy; 26 } 27 }; 28 } 29 30 protected void setRepository(SimpleRepository repository) { 31 this.repository = repository; 32 } 33 34 public SimpleRepository getRepository() { 35 return repository; 36 } 37 38 }
创建子类:使用时,new StudentRetrofit().create(StudentApi.class);生成动态代理类,通过RepositoryProxy 代理操作。
1 public class StudentRetrofit extends BaseRetrofit { 2 3 @Override 4 protected <T> T createApi(Class<T> clazz) { 5 RepositoryProxy retrofit = getProxyBuilder().baseurl("http://www.baidu.com") 6 .build(); 7 8 return retrofit.create(clazz); 9 } 10 }
RepositoryProxy 代理操作:
1 public class RepositoryProxy { 2 public <T> T create(Class<T> clazz) { 3 if (!clazz.isInterface()) { 4 throw new RuntimeException("retrofit Service not interface"); 5 } 6 7 return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, new ApiProxy(this)); 8 } 9 10 }
InvocationHandler对象:
1 public class ApiProxy implements InvocationHandler { 2 3 @Override 4 public Object invoke(Object proxy, Method method, Object... args) throws Throwable { 5 6 // If the method is a method from Object then defer to normal invocation. 7 if (method.getDeclaringClass() == Object.class) { 8 return method.invoke(this, args); 9 } 10 11 // 返回http请求对象 12 return post(method, args); 13 } 14 15 }
附录
retrofit官方文档
用 Retrofit 2 简化 HTTP 请求
使用Retrofit请求API数据
Retrofit2 更新指南
RESTful API 设计指南
Retrofit 源码的一个分析与导读