通过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的项目
当前题目:注解APT应用详解(手把手教你写ButterKnife工具)
分享链接:http://www.36103.cn/qtweb/news29/7679.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联