一、前言
经过前四篇的介绍,我们已经对注解比较熟悉了,下面介绍一个实战案例。
二、实战
2.1、背景介绍
在公司项目里,所有埋点里的pageName都是由Activity的context来获取Activity的名称来记录,
当我们需要修改pageName来与ios进行统一时,pageName挨个修改的工作量巨大,因此我们思考如何进行批量处理,或利用apt代码生成辅助。
2.2、代码
1、在project下建一个java module,名称为 count_annotation
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.CLASS)
public @interface Count {
/**
* BI页面名称
*/
String biPageName();
}
public class VVICCountReflect {
public static Map<String, String> mPageNameMap = new HashMap<>();
private static volatile VVICCountReflect mVVICCountReflect;
private VVICCountReflect() {
//app module
try {
Class<?> cls = Class.forName("com.lerendan.test.Count$$$app");
cls.newInstance();
} catch (Exception e) {
}
//module_user module
try {
Class<?> cls = Class.forName("com.lerendan.test.Count$$$module_user");
cls.newInstance();
} catch (Exception e) {
}
//module_shop module
try {
Class<?> cls = Class.forName("com.lerendan.test.Count$$$module_shop");
cls.newInstance();
} catch (Exception e) {
}
}
public static VVICCountReflect getInstance() {
if (mVVICCountReflect == null) {
synchronized (VVICCountReflect.class) {
if (mVVICCountReflect == null) {
mVVICCountReflect = new VVICCountReflect();
}
}
}
return mVVICCountReflect;
}
/**
* reset page name
*/
public void setPageName(String key, String pageName) {
if (key != null && !key.equals("") && pageName != null && !pageName.equals("")) {
mPageNameMap.put(key, pageName);
}
}
/**
* get page name
*/
public String getPageName(String key) {
if (key != null && !key.equals("")) {
return mPageNameMap.get(key);
}
return null;
}
}
2、新建一个 java module,名字为 count_compiler
@AutoService(Processor.class)
public class CountProcessor extends AbstractProcessor {
private Map<String, String> mMap = new HashMap<>();
private Filer filer;
private String mModuleName = "";
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
filer = processingEnv.getFiler();
Map<String, String> map = processingEnv.getOptions();
if (map != null && map.size() > 0) {
mModuleName = map.get("moduleName");
}
}
@Override
public Set<String> getSupportedAnnotationTypes() {
HashSet<String> supportTypes = new LinkedHashSet<>();
supportTypes.add(Count.class.getCanonicalName());
return supportTypes;
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
collectInfo(roundEnvironment);
writeToFile();
return true;
}
/**
* 收集注解信息
*/
private void collectInfo(RoundEnvironment roundEnvironment) {
mMap.clear();
Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(Count.class);
for (Element element : elements) {
if (element.getKind() == ElementKind.CLASS) {
String biPageName = element.getAnnotation(Count.class).biPageName();
TypeElement typeElement = (TypeElement) element;
String simpleName = typeElement.getSimpleName().toString();
mMap.put(simpleName, biPageName);
}
}
}
/**
* 通过javapoet生成文件
*/
private void writeToFile() {
try {
MethodSpec.Builder constructor = MethodSpec.constructorBuilder().addModifiers(Modifier.PUBLIC)
.addStatement("addPageNameToMap()");
MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("addPageNameToMap")
.addModifiers(Modifier.PRIVATE)
.returns(void.class);
for (String simpleName : mMap.keySet()) {
String biPageName = mMap.get(simpleName);
methodBuilder.addStatement("$T.mPageNameMap.put($S, $S)", VVICCountReflect.class, simpleName, biPageName);
}
TypeSpec typeSpec = TypeSpec.classBuilder("Count$$$" + mModuleName).addModifiers(Modifier.PUBLIC)
.addMethod(constructor.build())
.addMethod(methodBuilder.build())
.build();
JavaFile javaFile = JavaFile.builder("com.weisheng.vvic", typeSpec).build();
javaFile.writeTo(filer);
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Count(biPageName = "test")
public class TestActivity extends Activity {
...
}
最后,如果项目中只有一个主 app module,则在 app.build 中引入下面两个就可以了
api project(':count_annotation')
annotationProcessor project(':count_compiler')
如果有多个module,则需要在每个module下添加上述配置,其中 api project(':count_annotation') 可以放在 base module 中,但annotationProcessor project(':count_compiler') 必须在每个 module 中都要添加