Retrofit实现的巧妙,以及对动态代理、适配模式和泛型的运用真是让人佩服至极,通过动态代理以及适配让一个带有注解的普通的接口转换成一个HttpRequest请求并使用OkHttpCall发送,真是太赞了,今天实现了一个简单retrofit方式的activity之间的跳转。一个小demo,分享一下。
首先,我们要定义一下注解:
//此注解是用来标注,跳转到的类是哪个模块的
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Path { String value(); }
//此注解是描述具体跳转到哪个类的
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Activity { Class value(); }
//此注解描述,要传递的参数的key值
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) public @interface Parameter { String value(); }接下来就是一个Service的接口,跟Retrofit的HttpService完全一样public interface RouterService {
//要跳转到OtherActivity这个页面,且该页面是在主模块中实现,并且带para1和para2两个String型参数过去 @Path("main") @Activity(OtherActivity.class) public Intent gotoOtherActivity(Context context,@Parameter("para1") String para1, @Parameter("para2") String para2); }接口定义就完成了,接下来就是最核心东西,将这个接口翻译成Intent对象并返回public final class RouterUtil { private static final Charset UTF_8 = Charset.forName("UTF-8"); public <T> T create(final Class<T> service){//使用动态代理的方式返回泛型T对象,且在InvocationHandler类中将方法转换成intent并返回 return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[]{service}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Intent intent = new Intent(); Class toClz = null;//这里并没有出Path这个注解,因为是demo,还没有用到,这里只处理了Activity注解 Activity actAnnotation = method.getAnnotation(Activity.class); if(actAnnotation != null){//获取到要跳转到页面的class文件 toClz = actAnnotation.value(); }
//获取到该方法的所有的参数类型 Class[] paraTypes = method.getParameterTypes(); for (int i = 0; i < paraTypes.length; i++) { Class para = paraTypes[i]; if(para == Context.class){ intent.setClass((Context) args[i],toClz); } if(para == String.class){//获取每个参数的注解,并捕捉到Parameter注解,因为是demo,所以直接以//anno[0]的方式获取了Annotation[] anno = method.getParameterAnnotations()[i]; if(anno[0] instanceof Parameter){//获取到了((Parameter)anno[0]).value()为key,(String)args[i]为参数值 intent.putExtra(((Parameter)anno[0]).value(),(String)args[i]); } } } return intent; } }); } public static final class Builder{ public Builder(){ } public RouterUtil build(){ return new RouterUtil(); } } }动态代理中invoke方法里完成了普通接口-Intent对象的转换,接下来是调用,//返回其实不是RouterService接口的对象,而是一个代理接口的对象
RouterService routerService = new RouterUtil.Builder().build().create(RouterService.class);Intent intent = routerService.gotoOtherActivity(MainActivity.this,"param1","param2") startActivity(intent);有没有疑问说,routerService.gotoOtherActivity简单的调用一下怎么就转换成了intent对象了呢,这仅仅是一个未被实现的接口里的方法而已啊。这就是动态代理的作用,当我们使用
RouterService routerService = new RouterUtil.Builder().build().create(RouterService.class);这行代码创建的routerService这个对象,它已经不是原来的RouterService的对象,而是一个代理的对象,当执行其方法的时候,都要执行invoke方法里面的代码,才会真正会转换成Inetnt对象。这样跳转可以隐藏真正的目标Activity。