本人从事开发工作也有多年,目前坐标湖南长沙,以前在各种平台也发过一些文章但是都没有坚持下来;
我初步规划是写一个完整的项目系列文章期望能坚持下来。
为什么会想到要写呢?
其一、眨眼就到了而立之年,觉得自己记忆力也是下降久做过的东西总是记不起,果然是好记性不如烂笔头。
其二、这么多年白嫖了网上很多的文章,视频,一直觉得应该分享一些东西但总是沉不下心去做。
其三、可能写的不好至少也留下一些东西,也是希望能帮助到一些朋友。
最近在研究鸿蒙系统写了一些简单的东西,鸿蒙的有些UI操作,比如findComponentById,setClickedListener 这些比较繁琐于是就尝试用APT做一个尝试实现一个简单的butterknife。
如不知道请参考Hello world: 鸿蒙初尝试.
我这里选择了Empty Feature Ability(JAVA)
鸿蒙编译器做到修改布局后及时编译。这个时候我们可以做如下操作!
1.要么运行一次。
2.用命令行运行一次Gradle编译命令
3.当然我们不用这么麻烦直接图形化点一下Gradle执行
添加几个断点预备Debug看看
运行结果 证明
点击第二个控件后
证明这样写在鸿蒙系统中也是没有问题的。接下来我们只需要试试用APT生成MainAbilitySlice$ViewBinding类后可不可以调用到就可以了。
添加ButterKnifeProcessor
添加需要的包引用
在 entry中添加对于生成的库引用
修改ButterKnifeProcessor文件
package com.lyl.butterknife.compiler;
import com.google.auto.service.AutoService;
import com.lyl.butterknife.annotations.BindView;
import com.lyl.butterknife.annotations.OnClick;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.*;
@AutoService(Processor.class)
public final class ButterKnifeProcessor extends AbstractProcessor {
private Filer mFiler;
private Elements mElementUtils;
private Messager mMessager;
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
mElementUtils = processingEnv.getElementUtils();
mMessager = processingEnv.getMessager();
mFiler = processingEnv.getFiler();
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
private Set> getSupportedAnnotations() {
Set> annotations = new LinkedHashSet<>();
annotations.add(BindView.class);
annotations.add(OnClick.class);
return annotations;
}
@Override
public Set getSupportedAnnotationTypes() {
Set types = new LinkedHashSet<>();
for (Class extends Annotation> annotation : getSupportedAnnotations()) {
types.add(annotation.getCanonicalName());
}
return types;
}
@Override
public boolean process(Set extends TypeElement> typeElements, RoundEnvironment env) {
Map> elementListMap = findAndParseTargets(env);
for (Map.Entry> entry : elementListMap.entrySet()) {
Element enclosingElement = entry.getKey();
List viewBindElements = entry.getValue();
String activityClassNameStr = enclosingElement.getSimpleName().toString();
ClassName activityClassName = ClassName.bestGuess(activityClassNameStr);
TypeSpec.Builder classBuilder = TypeSpec.classBuilder(activityClassNameStr + "$ViewBinding")
.addModifiers(Modifier.FINAL, Modifier.PUBLIC);
buildElementConstructorMethod(activityClassName, classBuilder, viewBindElements);
try {
String packageName = mElementUtils.getPackageOf(enclosingElement).getQualifiedName().toString();
JavaFile.builder(packageName, classBuilder.build())
.build().writeTo(mFiler);
} catch (IOException e) {
e.printStackTrace();
System.out.println(e.getMessage());
}
}
return true;
}
private void buildElementConstructorMethod(ClassName activityClassName, TypeSpec.Builder classBuilder, List buildObject) {
MethodSpec.Builder constructorMethodBuilder = MethodSpec.constructorBuilder()
.addParameter(activityClassName, "target",Modifier.FINAL).addModifiers(Modifier.PUBLIC);
for (BuildObject object : buildObject) {
assembleConstructorMethod(constructorMethodBuilder, object);
}
classBuilder.addMethod(constructorMethodBuilder.build());
}
private void assembleConstructorMethod(MethodSpec.Builder constructorMethodBuilder, BuildObject buildObject) {
System.out.println(buildObject.clazz == BindView.class);
if (buildObject.clazz == BindView.class) {
String filedName = buildObject.element.getSimpleName().toString();
String type = buildObject.element.asType().toString();
System.out.println(filedName);
System.out.println(type);
int resId = buildObject.element.getAnnotation(BindView.class).value();
constructorMethodBuilder.addStatement("target.$L =($L) target.findComponentById($L)", filedName, type, resId);
} else if (buildObject.clazz == OnClick.class) {
String filedName = buildObject.element.getSimpleName().toString();
String type = buildObject.element.asType().toString();
System.out.println(filedName);
System.out.println(type);
int[] resIds = buildObject.element.getAnnotation(OnClick.class).value();
System.out.println(resIds);
for (int resId : resIds) {
constructorMethodBuilder.addStatement(" target.findComponentById($L).setClickedListener(new ohos.agp.components.Component.ClickedListener() {@Override public void onClick(ohos.agp.components.Component component) {target.$N(component);}})", resId, filedName);
}
}
}
private Map> findAndParseTargets(RoundEnvironment env) {
Map> elementListMap = new LinkedHashMap<>();
for (Class extends Annotation> clazz : getSupportedAnnotations()) {
for (Element element : env.getElementsAnnotatedWith(clazz)) {
try {
Element enclosingElement = element.getEnclosingElement();
List elements = elementListMap.get(enclosingElement);
BuildObject buildObject = new BuildObject(element, clazz);
if (elements == null) {
elements = new ArrayList<>();
}
System.out.println(enclosingElement.getSimpleName());
System.out.println(element.getSimpleName());
elements.add(buildObject);
elementListMap.put(enclosingElement, elements);
} catch (Exception e) {
}
}
}
return elementListMap;
}
}
其中用到的一个BuildObject
package com.lyl.butterknife.compiler;
import javax.lang.model.element.Element;
public class BuildObject {
Element element;
Class clazz;
public BuildObject(Element element, Class clazz) {
this.element = element;
this.clazz = clazz;
}
public Element getElement() {
return element;
}
public void setElement(Element element) {
this.element = element;
}
public Class getClazz() {
return clazz;
}
public void setClazz(Class clazz) {
this.clazz = clazz;
}
}
尝试失败!
当然我们可以采取一些其他方式让他打包进去…
但我们现在确实是失败了
具体为什么鸿蒙的IDE为什么没有把他编译进去的原因暂时没有去深究。
如果朋友找到原因或者我有哪个地方弄错了可以联系我!
生成代码的如果一些不懂得可以结合下面这篇文章查看
链接: 搭建Android客户端APP架构——《编译时APT技术》
链接: Javapoet说明
链接: 这个项目的源码地址
//TODO 给我感觉写代码远比写文章要轻松....致敬所有写文分享的人
我是先好Demo,再写文章的,写文章的时间远要比写Demo的时间久。
这篇文章主要写了一些简单的鸿蒙 APT的尝试,如有不懂之处或者写得不甚明了的地方可以留言。