Android 利用apt生成代码,实现butterKnife控件查找功能

了解了butterknife的完毕原理后,研讨了一下apt技能,接着自己查阅相关资料,撸了一遍apt的完毕进程,因为看的资料比较老源码精灵旧,完毕进程较为曲折,所以把自己的完毕进程记载一下,便当新学习的小伙伴绕开这些坑。

ATP(Annotation processing tool)

Annotation processing tool也便是注解处理器了,原理是枸杞根据注解在代码编译的时分去生成相应的功用代码文件,打包的时分会跟着其他的源码一同打包成class文件,这样就避免了那些功appointment能在工作时全部用反射去完毕,然后提高了app的性能。

首要新建一个工程,然后新建一个java library module,取名binder_annotation,这儿咱们专门用来寄存Annotation文件,接着自定义一个宫颈癌Annotation,取名Bind源码精灵View:

@Retention(RetentionPolicy.CLASS)
@Target(ElementTyp源码编辑器e.FIELD)
public @interface BindView {
int va源码是什么意思lue();
}

接着新建另一个java library module,取名binder_compiler,咱们在这儿做注解处理的作业,和生成相应的java文件的操作,
在这approve个module的gradle文件里增加如下配备:

plugins {
id 'java-library'
}
java {
sourceCompatibility = JavaVersion.VERSION_源码之家1_7
targetCompatibility = JavaVersion.VERSION_1_7
}
dependen实例化是什么意思cies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
//AutoService 首要的效果是注解 processor 类,并对其生成 META-INF 的配备信息。
implementation 'com.google.auto.service:auto-service:1.0-rc6'
//处理gradle的版别源码编辑器bug,不增加会导致咱们的process类不被调用
annotationProcessor 'com.google.auto.service:auto-service:1.0-rc6'
//JavaPoet 这个库的首要效果便是帮忙咱们通过类调appointment用的办法来生成代码。
implementation 'com.squareuapprovep:javapoet:1.10.0'
implementation project(':binder_an源码notation')
}

留心:Android Plugin for Gradle: &gt缓存视频变成本地视频;3.3.2的时分要增加 :

anno实例化servlet类反常tationProcessor ‘com.google.auto.缓存service:auto-service:1.0-rc6′ 这行依赖,这实例化需求是gradle的一实例化个版别bug,高版其他gradle不会去调用咱们编写好的process类,我在这儿就陷进去好久。

app module下的gradle文件做如下配备:

dependencies {
implementappreciateation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompa缓存视频怎样转入相册t:appcompat:1.3.0'
implementation 'com.google.android.material:matapplicationerial:缓存视频怎样转入本地视频1.3.0'
implementation 'androidx.consappreciatetraintlayout:constraintlayout:2.0.4'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
annotationProcessor projeapprovect(':bin实例化是什么意思der_compilerapp下载')
implementa源码编辑器tion project(':binder_annotation')
}

接着新建BinderProcessor类,让它继承实例化servlet类反常AbstractProcessor,并加上@AutoService(Proc实例化servlet类反常essor.class)注解,这样它才会在代码编译期被执行:

@AutoService(Processor.class)
pub源码交易平台lic class BinderProcessor exteapprovends AbstractProcessor {
private Elements mElementUtils; ///处理Element的东西类
private HashMap<String,Bin实例化方针是什么意思derClassCreator&gt源码年代;  mCreatorMap = new工商银行客服电话 Has龚俊hMap<>();//结构器东西的缓存m缓存视频变成本地视频ap
}

重写相关办法:

 //初始化
@Ove工商银行rride
pub缓存视频兼并lic synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
//处理Elemen实例化一个类t的东西类,用于获取程序的元素,例如包、类、办法。
mElementUtils = processingEapprovenvironme源码分享网nt.getElementUtils();
}
//运用最新源码之家的版别
@Override
publ宫颈癌前期症状ic SourceVersion getSupportedSourceVersion() {
return SourceVersion.lapp下载atestSupported();
}
//支撑的注解类名集结,这儿咱们只做BindView的注解处宫颈癌前期症状理
@Override
public Set<String> getSupportedAnnotationTypes(缓存是什么意思) {
HashSet缓存视频怎样下载到手机相册&l缓存数据能够铲除吗t;Strin缓存视频在手机哪里找g> supportTypes = new LinkedHashSet<>();
supportTypes.add(B宫颈癌前期症状indView.class.getCanonicalName());
return supportTypes;
}缓存视频在手机哪里找

要点需求处理的办法是process(),相重视释在代码里,算是比较详细了,多看几遍应该看得懂:

@Overri实例化方针de
p工商银行客服电话ublic boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
//扫描整个工程里被BindView注解过的元素,会根据activity名来生成相应的东西类BinderClassCreator
//BinderClassCreator里包含了生成相应的activity的_ViewBinding类,里面有做了findVie枸杞wById的作业
Set<? extends Element> elements = r巩立姣oundEnvironment.getElementsAnnotatedWith(BindVie缓存数据能够铲除吗w.class缓存);
fo实例化需求r(Element element:elements){
VariableElemeapplicationnt variableElement = (Va工商银行riableElement) element;//强转
//回来此元素直接封装(非严峻意义上)的元素。
//类或接口被以为用于封装它直接声明的字段、办法、结构办法和成员类型
//这儿便是获取封装特征元素的类元素
TypeElement classElement = (TypeElement) variableElement.getEnclosingElement();
//获取简略类名
String fullCl缓存视频兼并assName = classElement.getQualifiedName().toStriGong();
//先在map缓存里approach源码年代培训怎样样BinderClassCreator
BinderClassCreator creator = mCreatorMap.ge缓存视频在手机哪里找t(fullClassName);
if(creator == null){
creator = new BinderClassCreator(mElementUtils.getPackaapplegeOf(classElement),classElement);
//保存在map里
mCreatorMap.put(fullClassName,c源码编辑器reator);
}
//获取元素注解信息
Bi工商银行ndView缓存视频怎样转入本地视频 bindAnnotation = variableElement.getAnnotation(BindView.class);
int id = bindAnnotation.value();
creator.putElement(id,variableElement);
}
//通过javaPoet构建生成java文件
for(Strinappstoreg key:mCreatorMap.keySet()){
BinderClassCreator classCreator = mCreator实例化一个类Map.get(keygoogle);
JavaFile javaFile = JavaFile.builder(classCreator.getmPackageName(), classCreator.generateJavaCode()).build();
try {
javaFile.writ公积金eTo(processingEnv.getFiappointmentler());
} catch (IOException e) {
e.printStackTrace();
}
}
retur缓存视频兼并n false;
}

这儿用到宫颈癌前期症状一个Bi源码精灵nderClassCreator类,用来狗狗币帮忙构建相应activity__ViewBinding类的东西:

/**
*源码年代培训怎样样 @author: lookey
* @date: 2021/5/25
* 用来生成_BinderView类的东西类
*/
public实例化方针是什么意思 class BinderClassCreator {
publappreciateic static final String ParamNappearame = "vi缓存视频怎样转入相册ew";
private TypeEle实例化方针的关键字ment mTypeElement;//类元素
private String mPackageName;application
private String mBinderClassName;
private Ha宫颈癌shMap<Integer, Variable源码编辑器Eleme宫颈癌nt> mVariableElement = new HashMap<>();
public BinderClassCreator(PackageElement mPackageElement, Typ缓存eElement mTypeElement) {
this.mTypeElement = mTypeElement;
this.mPackageNam缓存视频怎样下载到手机相册e = mPacka缓存视频兼并geElement.实例化需求getQualifiedName().toString();
th缓存视频在手机哪里找is.mB实例化servlet类反常inderClassName = mTypeElement.getSimpleNam实例化需求e(源码资源站).实例化是什么意思toString()+"_ViewBinding";
}
public void putElement(int id,VariableElement variableE实例化方针的关键字lement){
mV源码分享网ariableElement.put(id,variableElement);
}
public String getmPac缓存视频怎样转入本地视频kageNa缓存视频怎样转入本地视频me() {
r狗狗币eturn mPackageName;
}宫颈癌前期症状
//生成java类,及相源码资本应的办法
public TypeSpec generateJavaCode(){
return TypeSpec.classBuilder(mBinderClassName)
.addModifiers(源码交易平台Modifier.PUBLIC) //public修饰
.addMethod(generateMethod()) //增加办法
.build();
}
private MethodSpec generateMethod(){缓存是什么意思
//获取类名
ClassName className = ClassName.best缓存视频怎样下载到手机相册Guess(mTypeElement.getQualifiedName().toString());
return MethodSpec.methodBuilder("bindView")
.addModifiers(Modifier.PUBLIC)
.returns(void.class)
.addParameter(className,ParamName)
.addCode(generateMethodCo实例化方针是什么意思d缓存视频怎样转入本地视频e())源码
.build();
}
private String generateMeapproachthodCode() {
StringB实例化方针有几种办法uilder code = new S源码精灵tringBuilder();
for (int id : mappointmentVariabl源码eElemapplicationent.keySet()) {
VariableElement variable缓存Element = mVariableElement.get(id缓存视频变成本地视频);
//运用注解的特征的称号
String name = variableElement.getSiGompleName().toString();
//运用注解的特征的类型
String type = variableEl实例化数组ement.asType().toString();
//view.name = (type)view狗狗币.findViewByIdapple(id)
String findVi实例化类ewCode = Param实例化servlet类反常Name + "." + name + "=(" + type + ")" + Param源码编辑器Name +
".findViewById(" + id + ");n";
code.append(findViewCode);
}
return code.toString();
}
}

再写一个东缓存视频兼并西类BinderViewTools 让咱们的activity调用,相似ButterKnife.bind(),通篇下来也就在这儿用到了反射:

/appearance**
* @author: lookey
* @date: 2021/5/25
*/
public class BinderViewTools {
public static void biappearnd(Activity activi实例化数组ty){
Class aClass = activit源码之家y.getClass();
try实例化 {
Class<?> bindClass = Class.forName(aClass.getCanonicalName() + "_ViewBinding");//找到生成的相应的bind类
Method method = bindClass.getMethod("bindView", aClass);
method.invoke(bindClass.newInstance(),a源码交易平台ctivity);
} catch (Exception e) {
e.printStackTr缓存数据能够铲除吗ace();
}
}
}

最后在activity运用一下,运用过程相似butterkn实例化需求ife:

package com.trendlab.aptex;
import androidx.appcompat.app.App源码之家CompatAc缓存数据能够铲除吗tivity;
import android.os.Bundle;
import android.widget.TextVie巩立姣w;
import com.trendlab.binder_annotation.BindView;
publ实例化类ic class MainAapp下载ctivity extends AppCompatAct缓存视频怎样转入相册ivity {
@Bin工商银行客服电话dView(R.id.tv111)
public TextView tv111;
@Override
protected void onCrea源码交易平台te(Bundl源码分享网e savedInstan缓存视频变成本地视频ceState) {
super.onCreate(savedInst缓存视频怎样下载到手机相册anceState);
setContentView(R实例化是什么意思.layout.ac缓存视频怎样转入本地视频tivity_main);
BinderViewTools.bind(this); //工作缓存时会去找到MainActivity_ViewBinding类,然后实例化一个方针,再调用findview()办法
tv111.setText("hello binder");
}
}

工作编译一下,一切正常的话会在app module下生成这个文工商银行件:

Android 使用apt生成代码,完成butterKnife控件查找功用

模拟器工作成功:

Android 使用apt生成代码,完成butterKnife控件查找功用

整体做完仍是比较清楚的,要点是实例化一个类对javaPoet的熟练运用,和生成java文件的process()办法的构思,调试进程中遇到不能生成java文件,或许提示写入重appointment复报错的状况能够检验invalidate caches/restart 重启studio。

完毕

有一同学习的小伙伴能够重视下我的大众号——❤️程序猿养成方案❤️ 每周会守时做技能分享。快参与和我一同学习吧!

发表评论

提供最优质的资源集合

立即查看 了解详情