美文网首页Android
基于apt实现自己的依赖注入框架

基于apt实现自己的依赖注入框架

作者: 大頭蝦Coder | 来源:发表于2019-04-15 10:20 被阅读0次

前置知识:Annotation注解

一,APT的介绍

APT英文全称:Android annotation process tool是一种处理注释的工具,它对源代码文件进行检测找出其中的Annotation,使用Annotation进行额外的处理。

Annotation处理器在处理Annotation时可以根据源文件中的Annotation生成额外的源文件和其它的文件(文件具体内容由Annotation处理器的编写者决定),APT还会编译生成源文件和原来的源文件,将它们一起生成class文件。简言之:APT可以把注解,在编译时生成代码。

二,APT的处理要素

注解处理器(AbstractProcess)+代码处理(javaPoet)+处理器注册(AutoService)+apt

三,使用APT来处理annotation的流程

1.定义注解(如@MyButterKnife)

2.定义注解处理器

3.在处理器里面完成处理方式,通常是生成java代码。

4.注册处理器

5.利用APT完成如下图的工作内容。

image

下面介绍如何利用apt技术实现自己的依赖注入框架

首先new一个project(主工程),再new一个名为Annotation的java library,build.gradle 如下


apply plugin: 'java-library'

dependencies { implementation fileTree(dir: 'libs', include: ['*.jar'])}

sourceCompatibility = "1.7"
targetCompatibility = "1.7"

编写如下的类:

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.CLASS)

public @interface MyButterKnife {

}


@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

public @interface Bind {

int value()default 0;

}

新建名为compiler的java library,build.gradle 如下


apply plugin:'java-library'

dependencies {

implementation fileTree(dir:'libs',include: ['*.jar'])

    implementation 'com.google.auto.service:auto-service:1.0-rc2'

    implementation 'com.squareup:javapoet:1.7.0'

    implementation project(':Annotation')

}

sourceCompatibility ="1.7"

targetCompatibility ="1.7"

注解处理器如下



@AutoService(Processor.class)
public class TestProcessor extends AbstractProcessor {
    private Elements elementUtils;
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        // 规定需要处理的注解
        return Collections.singleton(MyButterKnife.class.getCanonicalName());
    }
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        System.out.println("DIProcessor");
        Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(MyButterKnife.class);
        for (Element element : elements) {
            // 判断是否Class
            TypeElement typeElement = (TypeElement) element;
            List<? extends Element> members = elementUtils.getAllMembers(typeElement);
            MethodSpec.Builder bindViewMethodSpecBuilder = MethodSpec.methodBuilder("bindView")
                    .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
                    .returns(TypeName.VOID)
                    .addParameter(ClassName.get(typeElement.asType()), "activity");
            for (Element item : members) {
                Bind diView = item.getAnnotation(Bind.class);
                if (diView == null){
                    continue;
                }
                bindViewMethodSpecBuilder.addStatement(String.format("activity.%s = (%s) activity.findViewById(%s)",item.getSimpleName(),ClassName.get(item.asType()).toString(),diView.value()));
            }
            TypeSpec typeSpec = TypeSpec.classBuilder("DI" + element.getSimpleName())
                    .superclass(TypeName.get(typeElement.asType()))
                    .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
                    .addMethod(bindViewMethodSpecBuilder.build())
                    .build();
            JavaFile javaFile = JavaFile.builder(getPackageName(typeElement), typeSpec).build();
            try {
                javaFile.writeTo(processingEnv.getFiler());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return true;
    }
    private String getPackageName(TypeElement type) {
        return elementUtils.getPackageOf(type).getQualifiedName().toString();
    }
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        elementUtils = processingEnv.getElementUtils();
    }
    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.RELEASE_7;
    }
}

主工程引入注解处理器和自定义注解,app/build.gradle 如下


apply plugin:'com.android.application'

//apply plugin: 'com.neenbedankt.android-apt'     高版本gradle中已弃用

android {

compileSdkVersion28

    defaultConfig {

applicationId"com.ql.aptapplication"

        minSdkVersion 15

        targetSdkVersion 28

        versionCode 1

        versionName "1.0"

        testInstrumentationRunner"android.support.test.runner.AndroidJUnitRunner"

    }

buildTypes {

release {

minifyEnabledfalse

            proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'

        }

}

}

dependencies {

implementation fileTree(dir:'libs',include: ['*.jar'])

implementation 'com.android.support:appcompat-v7:28.0.0'

    implementation 'com.android.support.constraint:constraint-layout:1.1.3'

    testImplementation 'junit:junit:4.12'

    androidTestImplementation 'com.android.support.test:runner:1.0.2'

    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

    implementation project(':Annotation')

    annotationProcessor project(':compiler')

}

主工程中使用


@MyButterKnife

public class MainActivity extends AppCompatActivity {

@Bind(R.id.textview)

TextView textView;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        DIMainActivity.bindView(this);

        textView.setText("hello annotation");

    }

}

点击rebuild ,可以在 /app/build/generated/source/apt/debug 目录下面看到生成的文件DIMainActivity


public final class DIMainActivity extends MainActivity {

public static void bindView(MainActivity activity) {

activity.textView = (android.widget.TextView) activity.findViewById(2131165319);

  }

}

reference

https://joyrun.github.io/2016/07/19/AptHelloWorld/

https://joyrun.github.io/2016/07/18/java-annotation/

相关文章

网友评论

    本文标题:基于apt实现自己的依赖注入框架

    本文链接:https://www.haomeiwen.com/subject/oeiywqtx.html