鸿蒙系统APP应用开发初尝试——编译时APT尝试!

背景

本人从事开发工作也有多年,目前坐标湖南长沙,以前在各种平台也发过一些文章但是都没有坚持下来;
我初步规划是写一个完整的项目系列文章期望能坚持下来。
为什么会想到要写呢?
其一、眨眼就到了而立之年,觉得自己记忆力也是下降久做过的东西总是记不起,果然是好记性不如烂笔头。
其二、这么多年白嫖了网上很多的文章,视频,一直觉得应该分享一些东西但总是沉不下心去做。
其三、可能写的不好至少也留下一些东西,也是希望能帮助到一些朋友。

说明

最近在研究鸿蒙系统写了一些简单的东西,鸿蒙的有些UI操作,比如findComponentById,setClickedListener 这些比较繁琐于是就尝试用APT做一个尝试实现一个简单的butterknife。

开始尝试

首先建立一个JAVA项目

如不知道请参考Hello world: 鸿蒙初尝试.

在这里插入图片描述
我这里选择了Empty Feature Ability(JAVA)

添加注解模块

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
添加BindView和OnClick注解
在这里插入图片描述
在这里插入图片描述

先试试在鸿蒙APP里面添加注解标记

去除不需要的代码

在这里插入图片描述

新建布局文件夹

在这里插入图片描述

添加布局文件

在这里插入图片描述

将这个布局添加引用到MainAbilitySlice

在这里插入图片描述
鸿蒙编译器做到修改布局后及时编译。这个时候我们可以做如下操作!
1.要么运行一次。
2.用命令行运行一次Gradle编译命令
3.当然我们不用这么麻烦直接图形化点一下Gradle执行
在这里插入图片描述

运行成功后就可以找到了

在这里插入图片描述

添加引用注解模块

在这里插入图片描述

完善添加注解代码

在这里插入图片描述

手动写一个将要生成试试可不可以实现运行效果

添加一个MainAbilitySlice$ViewBinding代码

在这里插入图片描述

添加butterknife模块

在这里插入图片描述
在这里插入图片描述

添加一个反射获取MainAbilitySlice$ViewBinding的类

在这里插入图片描述

添加几个断点预备Debug看看

添加butterknife模块引用以及添加调用

模块引用
在这里插入图片描述
添加调用
在这里插入图片描述

Debug运行试试看

在这里插入图片描述
在这里插入图片描述
运行结果 证明
在这里插入图片描述
在这里插入图片描述
点击第二个控件后
在这里插入图片描述
在这里插入图片描述
证明这样写在鸿蒙系统中也是没有问题的。接下来我们只需要试试用APT生成MainAbilitySlice$ViewBinding类后可不可以调用到就可以了。

试试采用APT生成MainAbilitySlice$ViewBinding

创建butterknife_compiler模块

在这里插入图片描述
添加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<Class<? extends Annotation>> getSupportedAnnotations() {
        Set<Class<? extends Annotation>> annotations = new LinkedHashSet<>();
        annotations.add(BindView.class);
        annotations.add(OnClick.class);
        return annotations;
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> 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<Element, List<BuildObject>> elementListMap = findAndParseTargets(env);
        for (Map.Entry<Element, List<BuildObject>> entry : elementListMap.entrySet()) {
            Element enclosingElement = entry.getKey();
            List<BuildObject> 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> 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<Element, List<BuildObject>> findAndParseTargets(RoundEnvironment env) {
        Map<Element, List<BuildObject>> elementListMap = new LinkedHashMap<>();
        for (Class<? extends Annotation> clazz : getSupportedAnnotations()) {
            for (Element element : env.getElementsAnnotatedWith(clazz)) {
                try {
                    Element enclosingElement = element.getEnclosingElement();
                    List<BuildObject> 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;
    }
}

执行生成MainAbilitySlice$ViewBinding

执行前把之前自己手写的类改个名
在这里插入图片描述

执行命令
在这里插入图片描述

找找MainAbilitySlice$ViewBinding是否生成

在这里插入图片描述

运行一下试试,看能不能正常运行…

这里没有运行结果图…因为崩溃了…
错误是
在这里插入图片描述

大概查看了一下崩溃原因…

虽然标记中点位置都生成了但javac里面并没有。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

结果

尝试失败!
当然我们可以采取一些其他方式让他打包进去…
但我们现在确实是失败了
具体为什么鸿蒙的IDE为什么没有把他编译进去的原因暂时没有去深究。
如果朋友找到原因或者我有哪个地方弄错了可以联系我!
生成代码的如果一些不懂得可以结合下面这篇文章查看
链接: 搭建Android客户端APP架构——《编译时APT技术》
链接: Javapoet说明

源码

链接: 这个项目的源码地址

吐槽


//TODO 给我感觉写代码远比写文章要轻松....致敬所有写文分享的人
我是先好Demo,再写文章的,写文章的时间远要比写Demo的时间久。
这篇文章主要写了一些简单的鸿蒙 APT的尝试,如有不懂之处或者写得不甚明了的地方可以留言。
  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值