目录
- 模块间交互
- APT介绍与使用
- APT高阶用法JavaPoet
模块间交互
常见的交互方式
1)EventBus一对一通讯,会造成Bean对象泛
2)反射技术 维护成本较高,高版本容易出现@hide限
3)隐式意图 维护成本较高,action比较难以维护
4) 广播 7.0后需要动态注册
5)类加载器 需要全类名路径
解决方案
类加载模式
public void jumpApp(View v){
try {
//通过全类名的方式进行跳转
Class<?> clzz = Class.forName("com.canjun.myapplication.MainActivity");
Intent intent = new Intent(this,clzz);
startActivity(intent);
}catch (Exception e){
}
}
全局map记录的方式
-
在公共模块(common模块)添加全局记录类
/** * RecorderPathManager * 记录全局的path信息 * * @author zfc * @date 2020-01-09 */ public class RecorderPathManager { private static Map<String, List<PathBean>> paths = new HashMap<>(); /** * 根据组名和路径名记录字节码信息 * @param groupName * @param pathName * @param clazz */ public static void joinGroup(String groupName,String pathName,Class clazz){ List<PathBean> path = paths.get(groupName); if(path==null){ //添加 path = new ArrayList<>(); paths.put(groupName,path); }else { for (PathBean p: path){ if(p.getPath().equals(pathName)){ return; } } } path.add(new PathBean(pathName,clazz)); } /** * 获取目标字节码对象 * @param groupName 组名 * @param pathName 路径名 * @return */ public static Class getTargetClass(String groupName,String pathName){ List<PathBean> path = paths.get(groupName); if(path==null){ return null; } for (PathBean p: path){ if(p.getPath().equals(pathName)){ return p.getClzz(); } } return null; } } /** * PathBean * * 记录Activity字节码及其路径 * 例如 * path:'order/OrderMainActivity' * clzz: OrderMainActivity.class * * @author zfc * @date 2020-01-09 */ public class PathBean { private String path; private Class clzz; public PathBean(String path, Class clzz) { this.path = path; this.clzz = clzz; } public String getPath() { return path; } public void setPath(String path) { this.path = path; } public Class getClzz() { return clzz; } public void setClzz(Class clzz) { this.clzz = clzz; } }
-
在应用启动时,添加需要记录的字节码对象
/** * MyApp * * @author zfc * @date 2020-01-09 */ public class MyApp extends BaseApplication { @Override public void onCreate() { super.onCreate(); //注册activity RecorderPathManager.joinGroup("app","MainActivity",MainActivity.class); RecorderPathManager.joinGroup("order","OrderMainActivity", OrderMainActivity.class); RecorderPathManager.joinGroup("personal","PersonalMainActivity", PersonalMainActivity.class); } }
-
在页面跳转时,使用字节码对象
try { Class<?> clzz = RecorderPathManager.getTargetClass("app","MainActivity"); Intent intent = new Intent(this, clzz); startActivity(intent); }catch (Exception e){ }
APT介绍与使用
APT是什么
结构体语言
语言元素分类
常用的API
APT基本使用
-
环境描述
a.创建java library 名为compiler
b.为compiler添加依赖
// 注册注解,并对其生成META-INF的配置信息,rc2在gradle5.0后有坑 // As-3.2.1 + gradle4.10.1-all + auto-service:1.0-rc2 // implementation 'com.google.auto.service:auto-service:1.0-rc2' // As-3.4.1 + gradle5.1.1-all + auto-service:1.0-rc4 compileOnly'com.google.auto.service:auto-service:1.0-rc4' annotationProcessor'com.google.auto.service:auto-service:1.0-rc4' implementation project(':annotation')
-
创建注解处理器
/* * 通过autoService通过生成文件 */ @AutoService(Processor.class) @SupportedAnnotationTypes({"com.canjun.annotation.ARouter"}) @SupportedSourceVersion(SourceVersion.RELEASE_7) @SupportedOptions({"content"}) //外部传入的参数 public class ARouterProcessor extends AbstractProcessor { /** * 操作Element的工具类 */ private Elements elementUtils; /** * 类信息工具类 */ private Types typesUtils; /** * 日志信息输出工具类 */ private Messager messager; /** * 文件生成器 */ private Filer filer; //初始化工作 @Override public synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); elementUtils = processingEnv.getElementUtils(); typesUtils = processingEnv.getTypeUtils(); messager = processingEnv.getMessager(); filer = processingEnv.getFiler(); //可以获取外部模块传入的参数 //传参方式见下小结 String content = processingEnv.getOptions().get("content"); messager.printMessage(Diagnostic.Kind.NOTE,content); } // // //需要处理的注解类型 // @Override // public Set<String> getSupportedAnnotationTypes() { // return super.getSupportedAnnotationTypes(); // } // // //jdk版本去编辑 // @Override // public SourceVersion getSupportedSourceVersion() { // return super.getSupportedSourceVersion(); // } // // //接收外部参数 // @Override // public Set<String> getSupportedOptions() { // return super.getSupportedOptions(); // } @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { }
-
通过AndroidModule向java library compiler传入参数
// 在gradle文件中配置选项参数值(用于APT传参接收) // 切记:必须写在defaultConfig节点下 javaCompileOptions { annotationProcessorOptions { arguments = [content : 'hello apt'] } }
-
AndroidModule使用注解处理器
a.gradle中依赖的声明
implementation project(':annotation') //使用注解处理器 annotationProcessor project(':compiler')
b.Activity中使用注解
@ARouter(path="/app/MainActivity") public class MainActivity extends AppCompatActivity { ... ... }
-
注解处理中核心方法的实现
@Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { if(annotations == null){ return false; } messager.printMessage(Diagnostic.Kind.NOTE,annotations.toString()); //获取被注解的类对象 Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(ARouter.class); for (Element e:elements){ //获取包名 String pkgName = elementUtils.getPackageOf(e).getQualifiedName().toString(); //获取类名 String className = e.getSimpleName().toString(); messager.printMessage(Diagnostic.Kind.NOTE,pkgName + ">>" + className); //生成ARouter文件 String finalClassName = className+"$$ARouter"; try { JavaFileObject sourceFile = filer.createSourceFile(pkgName+"."+finalClassName); Writer writer = sourceFile.openWriter(); //设置包名 writer.write("package "+pkgName + ";\n"); writer.write("public class "+finalClassName+" {\n"); writer.write("public static Class<?> findTargetClass(String pathName){\n"); //获取注解的path的value(注意) String path = e.getAnnotation(ARouter.class).path(); writer.write("if(pathName.equalsIgnoreCase(\""+path+"\")){\n"); writer.write("return "+className+".class;\n"); writer.write("}\n"); writer.write("return null;\n"); writer.write("}\n"); writer.write("}\n"); writer.close(); } catch (Exception ex) { ex.printStackTrace(); } } return true; }
-
验证注解处理器生成的类
通过build->make project
使用autoService注解 注解处理器,会在如下图中的位置生成注册信息。
APT高阶用法和JavaPoet
JavaPoet概述
JavaPoet是什么
JavaPoet运行环境
implementation 'com.squareup:javapoet:1.9.0'
// 注册注解,并对其生成META-INF的配置信息,rc2在gradle5.0后有坑
// As-3.2.1 + gradle4.10.1-all + auto-service:1.0-rc2
// implementation 'com.google.auto.service:auto-service:1.0-rc2'
// As-3.4.1 + gradle5.1.1-all + auto-service:1.0-rc4
compileOnly'com.google.auto.service:auto-service:1.0-rc4'
annotationProcessor'com.google.auto.service:auto-service:1.0-rc4'
JavaPoet常用类
javaPoet格式化字符串
使用javaPoet
要求 生成如下格式的代码
package com.canjun.myapplication;
public class MainActivity$$ARouter {
public static Class findTargetClass(String name){
if(name.equalsIgnoreCase("/app/MainActivity")){
return MainActivity.class;
}
return null;
}
}
javaPoet编写内容如下:
@AutoService(Processor.class)
@SupportedAnnotationTypes({"com.canjun.annotation.ARouter"})
@SupportedSourceVersion(SourceVersion.RELEASE_7)
@SupportedOptions({"content"})
public class ARouterProcessor extends AbstractProcessor {
private Elements elementUtils;
private Types typeUtils;
private Messager messager;
private Filer filer;
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
elementUtils = processingEnv.getElementUtils();
typeUtils = processingEnv.getTypeUtils();
messager = processingEnv.getMessager();
filer = processingEnv.getFiler();
Map<String, String> options = processingEnv.getOptions();
String content = options.get("content");
messager.printMessage(Diagnostic.Kind.NOTE, content);
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if(annotations==null||annotations.isEmpty()){
return false;
}
//获取被ARouter注解的类
Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(ARouter.class);
for (Element e : elements){
//获取e的包名
String pkgName = elementUtils.getPackageOf(e).getQualifiedName().toString();
//获取类名
String className = e.getSimpleName().toString();
String newFileName = className+"$$ARouter";
//通过javaPoet写新生成的文件
//javaPoet项目地址https://github.com/square/javapoet
try {
String pathName = e.getAnnotation(ARouter.class).path();
MethodSpec methodSpec = MethodSpec.methodBuilder("findTargetClass")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(Class.class)
.addParameter(String.class, "name")
//需要注意的是 语句中的参数 不需要显式添加“;”
.addStatement(" if(name.equalsIgnoreCase($S)){\n" +
" return $T.class;\n" +
" }\n" +
" return null", pathName, ClassName.get((TypeElement)e))
.build();
TypeSpec typeSpec = TypeSpec.classBuilder(newFileName)
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addMethod(methodSpec)
.build();
JavaFile javaFile = JavaFile.builder(pkgName,typeSpec)
.build();
javaFile.writeTo(filer);
} catch (IOException ex) {
ex.printStackTrace();
}
}
return true;
}
}
生成结果: