采用APT&RxJava造一辆RxBus
来源:互联网 发布:sql数据库编程 编辑:程序博客网 时间:2024/06/05 04:28
首先感谢以下文章:
APT:https://github.com/lizhaoxuan/Android-APT-Framework
反射:http://www.cnblogs.com/lzq198754/p/5780331.html
注解:http://www.cnblogs.com/linjiqin/archive/2011/02/16/1956426.html
还记当时在看RxJava的时候,有一个RxBus项目,而且没几行代码就能实现跟EventBus一样的功能,大概的代码如下:
public class RxBus { //private final PublishSubject<Object> _bus = PublishSubject.create(); // If multiple threads are going to emit events to this // then it must be made thread-safe like this insteadprivate final Subject<Object, Object> _bus = new SerializedSubject<>(PublishSubject.create()); public void send(Object o) { _bus.onNext(o); } public Observable<Object> toObserverable() { return _bus; } public boolean hasObservers() { return _bus.hasObservers(); }}
没错就是这么简单通过PublishSubject来发射事件,当然我们需要一个事件接收处理,通常如下:
_rxBus.toObserverable().subscribe(new Action1<Object>() { @Override public void call(Object event) { if (event instanceof RxBusDemoFragment.TapEvent) { _showTapText(); } } })
是的event就是我们收到的事件,这样虽然简单但是有个诟病,那就是一旦PublishSubject发射事件任何一个subscribe方法都会被调用,这也是为什么event instanceof RxBusDemoFragment.TapEvent需要这么一句来判断事件的类型。所以我们需要改良一下,将收到的Event事件只传递给具体注册了的界面去,类似于EventBus中的:
public void onEvent(Event event) { // code.. }
所以在看了EventBus的源码和Butternife源码后想按他们的思路在编译时加入代码,主要用到的知识点就是开头涉及的那些连接知识点。
整个项目的大概结构是:
注册-注销-接受事件
@Subscribe @BindRxBus public void onEvent(Event event) { Toast.makeText(this, "on Event", Toast.LENGTH_LONG).show(); } @Override protected void onCreate() { super.onStart(); RxBus.getInstance().register(this); } @Override protected void onDestroy() { super.onDestroy(); RxBus.getInstance().unregister(this); }
发送消息
RxBusDao.getInstance().post(new Event());
运行时注解
@Retention(RetentionPolicy.CLASS)@Target(ElementType.METHOD)public @interface BindRxBus {// int value() default -1;}
当Retention = RetentionPolicy.CLASS的时候,编译时注解,在编译时被识别并处理的注解。
APT代码生成
通过注解,获取必要信息,在项目中生成代码,运行时调用,和直接运行手写代码没有任何区别。
@AutoService(Processor.class)public class RxBusProcesser extends AbstractProcessor { private static final String TAG = "RxBusProcesser"; private Filer mFiler;// 文件相关辅导类 private Elements mElements;// 元素相关 private Messager mMessager;// 日志 private Map<String, GenerateClass> mAnnotatedClassMap = new HashMap<>(); @Override public synchronized void init(ProcessingEnvironment processingEnvironment) { super.init(processingEnvironment); System.out.println("==== RxBusProcesser -> init ===="); mFiler = processingEnvironment.getFiler(); mElements = processingEnvironment.getElementUtils(); mMessager = processingEnvironment.getMessager(); } /** * 声明支持的注释 */ @Override public Set<String> getSupportedAnnotationTypes() { System.out.println("==== RxBusProcesser -> getSupportedAnnotationTypes ===="); Set<String> types = new LinkedHashSet<>(); types.add(BindRxBus.class.getCanonicalName()); return types; } @Override public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) { System.out.println("==== RxBusProcesser -> process ===="); processBindRxBus(roundEnvironment); for (GenerateClass annotatedClass : mAnnotatedClassMap.values()) { try { info("Generating file for %s", annotatedClass.getFullClassName()); annotatedClass.generateJavaFile().writeTo(mFiler); } catch (IOException e) { System.out.println("Generate file failed, reason: %s" + e.getMessage()); return true; } } return true; } private void processBindRxBus(RoundEnvironment roundEnvironment) { for (Element element : roundEnvironment.getElementsAnnotatedWith(BindRxBus.class)) { if (element.getKind() == ElementKind.METHOD) { GenerateClass generateClass = getAnnotatedClass(element); } } } private GenerateClass getAnnotatedClass(Element element) { TypeElement classElement = (TypeElement) element.getEnclosingElement(); String fullClassName = classElement.getQualifiedName().toString(); GenerateClass annotatedClass = mAnnotatedClassMap.get(fullClassName); if (annotatedClass == null) { annotatedClass = new GenerateClass(classElement, mElements); mAnnotatedClassMap.put(fullClassName, annotatedClass); } return annotatedClass; } private void info(String msg, Object... args) { mMessager.printMessage(Diagnostic.Kind.NOTE, String.format(msg, args)); }}
要看懂代码需要了解一下xxxElement是什么意思。
package com.example;public class Foo { // TypeElement private int a; // VariableElement private Foo other; // VariableElement public Foo() {} // ExecuteableElement public void setA( // ExecuteableElement int newA // TypeElement ) { }}
感谢http://qiushao.net/2015/07/07/Annotation-Processing-Tool详解/
然后通过GenerateClass对象来生成代码:
public JavaFile generateJavaFile() { // 构建inject函数 public inject(final ) MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("inject")// 函数名称 .addModifiers(Modifier.PUBLIC)// 函数声明类型 .addAnnotation(Override.class)// 添加注释 .addParameter(TypeName.get(typeElement.asType()), "host", Modifier.FINAL);// 函数参数名 // 在inject函数中插入RxBus.register函数 methodBuilder.addStatement("$T.getInstance().register(host)", TypeUtil.RXBUS); // 生成一个xxx$$RxBus类 TypeSpec finderClass = TypeSpec.classBuilder(typeElement.getSimpleName() + "$$RxBus") .addModifiers(Modifier.PUBLIC) .addSuperinterface(ParameterizedTypeName.get(TypeUtil.IRXBUS, TypeName.get(typeElement.asType()))) .addMethod(methodBuilder.build()) .build(); String packageName = elements.getPackageOf(typeElement).getQualifiedName().toString(); return JavaFile.builder(packageName, finderClass).build(); }
封装使用
IRxBus iRxBus = mRxBuses.get(className); if (iRxBus == null) { Class<?> _class = Class.forName(className + "$$RxBus"); iRxBus = (IRxBus) _class.newInstance(); mRxBuses.put(className, iRxBus); } iRxBus.inject(o);
通过少量的反射,把一些复杂的反射以及代码在编译时就给生成出来,大大的增加了速度。
最后:学习APT简单记录,后期补充完整,先回家过年。
体验地址:
https://github.com/Neacy/RxBus_
- 采用APT&RxJava造一辆RxBus
- (九)RxJava:RxBus
- RxJava+RxBus的使用
- Retrofit+RxJava+OKhttp+RxBus
- RxJava自定义RxBus
- MVP、Retrofit、RxJava、RxBus
- RxBus----Rxjava实现EventBus
- 用RxJava实现RxBus
- 基于RxJava的RxBus
- Android RxJava 实现RxBus
- RxJava RxAndroid RxBus入门
- RxJava和RxBus代替EventBus
- RxJava使用示例: 实现Rxbus代替eventbus
- 【RxJava Demo分析】(四)RxBus
- Rxjava——使用RxBus替换EventBus
- RxJava实现事件总线——RxBus
- RxJava实现事件总线(RxBus)及详解
- RxBus和RxManager管理rxJava的生命周期
- Springmvc项目启动后定时执行某个方法
- 【C++】n_element的用法
- Linux(Centos)之安装tomcat并且部署Java Web项目
- ROS + Caffe 机器人操作系统框架和深度学习框架笔记 (機器人控制與人工智能)
- jq 命令行 Shell 处理json 格式数据 示例
- 采用APT&RxJava造一辆RxBus
- Android Activity间传自定义对象,Parcel代码自动生成工具
- MySQL 存储过程或者函数中传参数实现where id in(1,2,3,...)IN条件拼接
- zookeeper集群搭建
- Linux学习
- Spring注解之 @PostConstruct和 @PreDestroy
- textField详解
- Shell 文件包含
- Hadoop面试