通过APT实现一个功能,通过对View变量的注解,实现View的绑定

创新互联长期为上1000+客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为新华企业提供专业的成都做网站、成都网站制作、成都外贸网站建设,新华网站改版等技术服务。拥有十年丰富建站经验和众多成功案例,为您定制开发。
1、创建几个Library来声明
- Android Library:aptlibs 正常的写Android的lib
 - Java or Kotlin Library:aptlib-anno (专门放我们编写的注解)
 - Java or Kotlin Library :aptlib-processor (编写动态生成文件的逻辑)
 - aptlibs
 - plugins {
 - id 'com.android.library'
 - id 'kotlin-android'
 - }
 - aptlib-anno
 - plugins {
 - id 'java-library'
 - }
 - aptlib-processor
 - 是plugins {
 - id 'java-library'
 - }
 
这个要记清楚,很多博主估计自己都没有写过apt,分不清楚AndroidLib和javaLib
apt 本来java 提供的,另外 Android库中不允许继承AbstractProcessor
2 、定义注解-自定义注解
记住要在 aptlib-anno 库下面创建
- @Retention(RetentionPolicy.CLASS)
 - @Target(ElementType.FIELD)
 - public @interface BindView {
 - int value();
 - }
 
定义了运行时注解BindView,其中value()用于获取对应View的id;
3、定义注解处理器-动态生成关联文件
aptlib-processor 库
首先在本lib下添加依赖
- dependencies {
 - implementation 'com.google.auto.service:auto-service:1.0-rc2'
 - implementation project(':aptlib-anno')
 - }
 
创建BindViewProcessor
- @AutoService(Processor.class)
 - public class BindViewProcessor extends AbstractProcessor {
 - private Messager mMessager;
 - private Elements mElementUtils;
 - private Map
 mProxyMap = new HashMap<>(); - @Override
 - public synchronized void init(ProcessingEnvironment processingEnv) {
 - super.init(processingEnv);
 - mMessager = processingEnv.getMessager();
 - mElementUtils = processingEnv.getElementUtils();
 - }
 - @Override
 - public Set
 getSupportedAnnotationTypes() { - HashSet
 supportTypes = new LinkedHashSet<>(); - supportTypes.add(BindView.class.getCanonicalName());
 - return supportTypes;
 - }
 - @Override
 - public SourceVersion getSupportedSourceVersion() {
 - return SourceVersion.latestSupported();
 - }
 - @Override
 - public boolean process(Set extends TypeElement> set, RoundEnvironment roundEnv) {
 - mMessager.printMessage(Diagnostic.Kind.NOTE, "processing...");
 - mProxyMap.clear();
 - //得到所有的注解
 - Set extends Element> elements = roundEnvironment.getElementsAnnotatedWith(BindView.class);
 - for (Element element : elements) {
 - VariableElement variableElement = (VariableElement) element;
 - TypeElement classElement = (TypeElement) variableElement.getEnclosingElement();
 - String fullClassName = classElement.getQualifiedName().toString();
 - ClassCreatorProxy proxy = mProxyMap.get(fullClassName);
 - if (proxy == null) {
 - proxy = new ClassCreatorProxy(mElementUtils, classElement);
 - mProxyMap.put(fullClassName, proxy);
 - }
 - BindView bindAnnotation = variableElement.getAnnotation(BindView.class);
 - int id = bindAnnotation.value();
 - proxy.putElement(id, variableElement);
 - }
 - //通过遍历mProxyMap,创建java文件
 - for (String key : mProxyMap.keySet()) {
 - ClassCreatorProxy proxyInfo = mProxyMap.get(key);
 - try {
 - mMessager.printMessage(Diagnostic.Kind.NOTE, " --> create " + proxyInfo.getProxyClassFullName());
 - JavaFileObject jfo = processingEnv.getFiler().createSourceFile(proxyInfo.getProxyClassFullName(), proxyInfo.getTypeElement());
 - Writer writer = jfo.openWriter();
 - writer.write(proxyInfo.generateJavaCode());
 - writer.flush();
 - writer.close();
 - } catch (IOException e) {
 - mMessager.printMessage(Diagnostic.Kind.NOTE, " --> create " + proxyInfo.getProxyClassFullName() + "error");
 - }
 - }
 - mMessager.printMessage(Diagnostic.Kind.NOTE, "process finish ...");
 - return true;
 - }
 - }
 
- public class ClassCreatorProxy {
 - private String mBindingClassName;
 - private String mPackageName;
 - private TypeElement mTypeElement;
 - private Map
 mVariableElementMap = new HashMap<>(); - public ClassCreatorProxy(Elements elementUtils, TypeElement classElement) {
 - this.mTypeElement = classElement;
 - PackageElement packageElement = elementUtils.getPackageOf(mTypeElement);
 - String packageName = packageElement.getQualifiedName().toString();
 - String className = mTypeElement.getSimpleName().toString();
 - this.mPackageName = packageName;
 - this.mBindingClassName = className + "_ViewBinding";
 - }
 - public void putElement(int id, VariableElement element) {
 - mVariableElementMap.put(id, element);
 - }
 - /**
 - * 创建Java代码
 - * @return
 - */
 - public String generateJavaCode() {
 - StringBuilder builder = new StringBuilder();
 - builder.append("package ").append(mPackageName).append(";\n\n");
 - builder.append("import com.example.gavin.apt_library.*;\n");
 - builder.append('\n');
 - builder.append("public class ").append(mBindingClassName);
 - builder.append(" {\n");
 - generateMethods(builder);
 - builder.append('\n');
 - builder.append("}\n");
 - return builder.toString();
 - }
 - /**
 - * 加入Method
 - * @param builder
 - */
 - private void generateMethods(StringBuilder builder) {
 - builder.append("public void bind(" + mTypeElement.getQualifiedName() + " host ) {\n");
 - for (int id : mVariableElementMap.keySet()) {
 - VariableElement element = mVariableElementMap.get(id);
 - String name = element.getSimpleName().toString();
 - String type = element.asType().toString();
 - builder.append("host." + name).append(" = ");
 - builder.append("(" + type + ")(((android.app.Activity)host).findViewById( " + id + "));\n");
 - }
 - builder.append(" }\n");
 - }
 - public String getProxyClassFullName()
 - {
 - return mPackageName + "." + mBindingClassName;
 - }
 - public TypeElement getTypeElement()
 - {
 - return mTypeElement;
 - }
 - }
 
4、写工具类BindViewTools
在aptlib项目中写绑定类
- public class BindViewTools {
 - public static void bind(Activity activity) {
 - Class clazz = activity.getClass();
 - try {
 - Class bindViewClass = Class.forName(clazz.getName() + "_ViewBinding");
 - Method method = bindViewClass.getMethod("bind", activity.getClass());
 - method.invoke(bindViewClass.newInstance(), activity);
 - } catch (Exception e) {
 - e.printStackTrace();
 - }
 - }
 - }
 
5、主项目app中引入
- implementation project(path: ':aptlib')
 - annotationProcessor project(path: ':aptlib-process')
 
在MainActivity中,在View的前面加上BindView注解,把id传入即可
- public class MainActivity extends AppCompatActivity {
 - @BindView(R.id.tv)
 - TextView mTextView;
 - @BindView(R.id.btn)
 - Button mButton;
 - @Override
 - protected void onCreate(Bundle savedInstanceState) {
 - super.onCreate(savedInstanceState);
 - setContentView(R.layout.activity_main);
 - BindViewTools.bind(this);
 - mTextView.setText("bind TextView success");
 - mButton.setText("bind Button success");
 - }
 - }
 
1、APT技术其实就是自定义注解和注解处理器,在编译期间生成Java文件,类似于IOC控制反转,可以方便的进行解耦;
2、如果你也可以实现很多不同的项目,比如路由框架等等,后续也会写一些apt的项目
Copyright © 2009-2022 www.wtcwzsj.com 青羊区广皓图文设计工作室(个体工商户) 版权所有 蜀ICP备19037934号