栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【Android】APT

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【Android】APT

1,概述

平时使用的一些框架如dagger2、butterknife等,通过注解动态生成代码的技术,就是apt,本文将写一个简单demo,来演示apt基本使用;

2,实例

(1)创建java-libray

在android-studio4.0版本,创建一个java-libray module; 

创建两个,分别命名为apt-annotation、apt-processor

再创建一个android module,取名apt-library

项目结构如下,

 (2)在apt-annotation下创建注解,这儿选择class,即编译时;

@Retention(RetentionPolicy.CLASS)
@Target(value = {ElementType.FIELD})
public @interface DemoFindViewById {
    int value();
}

(3)在apt-processor模块导入依赖,

dependencies {
    implementation 'com.google.auto.service:auto-service:1.0-rc2'
    implementation project(':apt-annotation')
}

(4)创建DemoProcessor类,在process中写入即将生成的java代码

@AutoService(Processor.class)
public class DemoProcessor extends AbstractProcessor {
    @Override
    public boolean process(Set set, RoundEnvironment roundEnvironment) {
        return false;
    }
}

(5)完整DemoProcessor如下,

@AutoService(Processor.class)
public class DemoProcessor extends AbstractProcessor {

    private ProcessingEnvironment mProcessingEnvironment;

    private Map mCache = new HashMap<>();

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        this.mProcessingEnvironment = processingEnv;
    }

     @Override
    public Set getSupportedAnnotationTypes() {
        // 写入支持编译的注解
        Set supportTypes = new HashSet<>();
        supportTypes.add(DemoFindViewById.class.getCanonicalName());
        return supportTypes;
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        // 兼容到JDK最新版本
        return SourceVersion.latestSupported();
    }

    @Override
    public boolean process(Set set, RoundEnvironment roundEnvironment) {
        //动态生成java代码
        mProcessingEnvironment.getMessager().printMessage(Diagnostic.Kind.NOTE, "processing...");
        //获取所有@Demo的Element
        Set elements = roundEnvironment.getElementsAnnotatedWith(DemoFindViewById.class);
        for (Element element : elements) {
            VariableElement variableElement = (VariableElement) element;
            TypeElement typeElement = (TypeElement) variableElement.getEnclosingElement();
            String className = typeElement.getQualifiedName().toString();

            CreateClassProxy proxy = mCache.get(className);
            if (proxy == null) {
                proxy = new CreateClassProxy(mProcessingEnvironment.getElementUtils(), typeElement);
                mCache.put(className, proxy);
            }
            DemoFindViewById findViewById = variableElement.getAnnotation(DemoFindViewById.class);
            int id = findViewById.value();
            proxy.putElement(id,variableElement);
        }

        //创建java文件
        for (CreateClassProxy proxy : mCache.values()) {
            mProcessingEnvironment.getMessager().printMessage(Diagnostic.Kind.NOTE,"create code :" + proxy.getClassName());
            try {
                JavaFileObject javaFileObject = super.processingEnv.getFiler().createClassFile(proxy.getClassName(), proxy.getTypeElement());
                Writer writer = javaFileObject.openWriter();
                writer.write(proxy.generateJavaCode().toString());
                writer.flush();
                writer.close();
            } catch (IOException e) {
                mProcessingEnvironment.getMessager().printMessage(Diagnostic.Kind.NOTE,"fail code :" + proxy.getClassName());
            }
            mProcessingEnvironment.getMessager().printMessage(Diagnostic.Kind.NOTE,"finish code :" + proxy.getClassName());
        }
        return true;
    }
}

(6)生成代码proxy类,

CreateClassProxy,采用JavaPoet辅助生成代码;

public class CreateClassProxy {

    private String mClassName;
    private String mPackageName;
    private TypeElement mTypeElement;
    private final Map mVariableElementMap = new HashMap<>();

    public CreateClassProxy(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.mClassName = className + "_DemoBinding";
    }

    public void putElement(int id, VariableElement element) {
        mVariableElementMap.put(id, element);
    }

    public String getClassName() {
        return mClassName;
    }

    public String getPackageName() {
        return mPackageName;
    }

    public TypeElement getTypeElement() {
        return mTypeElement;
    }

    public TypeSpec generateJavaCode(){
        TypeSpec typeSpec = TypeSpec.classBuilder(mClassName)
                .addMethod(generateJavaMethod())
                .build();

        return typeSpec;
    }

    public MethodSpec generateJavaMethod(){
        //类名
        ClassName className = ClassName.bestGuess(mTypeElement.getQualifiedName().toString());

        MethodSpec.Builder builder = MethodSpec.methodBuilder("inject")//方法名
                .addModifiers(Modifier.PUBLIC)//限定符
                .returns(void.class)//返回值
                .addParameter(className, "className");//参数类型和参数名

        //迭代,加入代码行
        for (Integer id : mVariableElementMap.keySet()) {
            VariableElement element = mVariableElementMap.get(id);
            String name = element.getSimpleName().toString();
            String type = element.asType().toString();
            //代码块
            builder.addCode("className." + name + " = " + "(" + type + ")(((android.app.Activity)className).findViewById( " + id + "));");
        }

        return builder.build();
    }
}

(7)在apt-library写工具类,即通过反射调用已经生成的代码,

public class AptDemoInjector {

    public static void inject(Activity activity){
        try {
            Class target = Class.forName(activity.getClass().getName() + "_DemoBinding");
            Method inject = target.getMethod("inject", activity.getClass());
            inject.invoke(target.newInstance(),activity);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

(8)在app模块写入测试代码,

public class AptDemoActivity extends AppCompatActivity {

    private static final String TAG = "AptDemoActivity";

    @DemoFindViewById(R.id.demo_id)
    public TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_apt_demo);

        // 注入,自动生成代码
        AptDemoInjector.inject(this);

        Log.d(TAG, "inject: TextView ->" + textView);
    }
}

(9)点击rebuild,自动生成代码如下

import android.widget.TextView;
import com.zjw.demoapp.apt.AptDemoActivity;

class AptDemoActivity_DemoBinding {
    AptDemoActivity_DemoBinding() {
    }

    public void inject(AptDemoActivity className) {
        className.textView = (TextView)className.findViewById(2131230864);
    }
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/678827.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号