dagger2结合apt自动生成注入代码搭建mvp

xiaoxiao2021-02-28  61

大家使用dagger2时候,通常要写一些注入代码,就算是再base类里面些, 当有新添加还有做修改。。其实倒也不麻烦,但是自动生成注入还是蛮爽的,像spring那样。。

本文分三部分来说吧。

第一部分是dagger2简单应用用一个mvp架构来做例子第二部分是apt生成代码第三部分是apt自动生成代码 再为dagger2提供注入。 结合第第一个和第二个来看。 dagger需要我们手写Component,和初始化代码。 新建activity还是有点麻烦。用上apt只要一个注解,就会自动生成Component类 和初始化代码,使用dagger真正更简单。

首先时创建一个java工程,跟第二部分apt生成代码一样。创建2个注解,这里分别时用来标注activity和fragment的。

@Retention(RetentionPolicy.CLASS) @Target(ElementType.TYPE) public @interface ActivityInject { } @Retention(RetentionPolicy.CLASS) @Target(ElementType.TYPE) public @interface FragmentInject { }

然后还是新建一个java工程,用来做注解处理器和其他类 总共2个核心类。一个时注解处理器,一个辅助文件生成的。 首先看注解处理器、

package com.spc; import com.google.auto.service.AutoService; import java.lang.annotation.Annotation; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import java.util.TreeMap; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.Filer; import javax.annotation.processing.Messager; import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.Processor; import javax.annotation.processing.RoundEnvironment; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.TypeElement; import javax.lang.model.util.Elements; import javax.tools.Diagnostic; /** * Created by spc on 17/6/6. */ @AutoService(Processor.class) public class ActivityInjectProcesser extends AbstractProcessor { private Filer mFiler; //文件相关的辅助类 private Elements mElementUtils; //元素相关的辅助类 许多元素 private Messager mMessager; //日志相关的辅助类 private Map<String, AnnotatedClass> mAnnotatedClassMap; @Override public synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); mFiler = processingEnv.getFiler(); mElementUtils = processingEnv.getElementUtils(); mMessager = processingEnv.getMessager(); mAnnotatedClassMap = new TreeMap<>(); } //扫描到注解会执行这里 @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { mAnnotatedClassMap.clear(); try { processActivityCheck(roundEnv); processFragmentCheck(roundEnv); } catch (Exception e) { e.printStackTrace(); error(e.getMessage()); } for (AnnotatedClass annotatedClass : mAnnotatedClassMap.values()) { try { Class fgAnType = Class.forName(TypeUtil.ANNOTATION_FRAGMENT_PATH); Class acAnType = Class.forName(TypeUtil.ANNOTATION_PATH); if (annotatedClass.getmTypeElement().getAnnotation(fgAnType) != null) { annotatedClass.generateFragmentDaggerFile().writeTo(mFiler); annotatedClass.generateFragmentFile().writeTo(mFiler); } else if (annotatedClass.getmTypeElement().getAnnotation(acAnType) != null){ annotatedClass.generateActivityDaggerFile().writeTo(mFiler); annotatedClass.generateActivityFile().writeTo(mFiler); } } catch (Exception e) { error("Generate file failed, reason: %s", e.getMessage()); } } return true; } private void processActivityCheck(RoundEnvironment roundEnv) throws IllegalArgumentException, ClassNotFoundException { //check ruleslass forName(String className for (Element element : roundEnv.getElementsAnnotatedWith((Class<? extends Annotation>) Class.forName(TypeUtil.ANNOTATION_PATH))) { if (element.getKind() == ElementKind.CLASS) { getAnnotatedClass(element); } else error("ActivityInject only can use in ElementKind.CLASS"); } } private void processFragmentCheck(RoundEnvironment roundEnv) throws IllegalArgumentException, ClassNotFoundException { //check ruleslass forName(String className for (Element element : roundEnv.getElementsAnnotatedWith((Class<? extends Annotation>) Class.forName(TypeUtil.ANNOTATION_FRAGMENT_PATH))) { if (element.getKind() == ElementKind.CLASS) { getAnnotatedClass(element); } else error("FragmentInject only can use in ElementKind.CLASS"); } } private AnnotatedClass getAnnotatedClass(Element element) { // tipe . can not use chines so .... // get TypeElement element is class's --->class TypeElement typeElement = (TypeElement) element // get TypeElement element is method's ---> TypeElement typeElement = (TypeElement) element.getEnclosingElement(); TypeElement typeElement = (TypeElement) element; String fullName = typeElement.getQualifiedName().toString(); AnnotatedClass annotatedClass = mAnnotatedClassMap.get(fullName); if (annotatedClass == null) { annotatedClass = new AnnotatedClass(typeElement, mElementUtils, mMessager); mAnnotatedClassMap.put(fullName, annotatedClass); } return annotatedClass; } @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); } //这个方法,返回要处理什么注解 的一个set集合 @Override public Set<String> getSupportedAnnotationTypes() { Set<String> types = new LinkedHashSet<>(); types.add(TypeUtil.ANNOTATION_PATH); types.add(TypeUtil.ANNOTATION_FRAGMENT_PATH); return types; } private void error(String msg, Object... args) { mMessager.printMessage(Diagnostic.Kind.ERROR, String.format(msg, args)); } private void log(String msg, Object... args) { mMessager.printMessage(Diagnostic.Kind.NOTE, String.format(msg, args)); } }

然后编译时候生成类的 代码

package com.spc; import com.spc.TypeUtil; import com.squareup.javapoet.AnnotationSpec; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.JavaFile; import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; import javax.annotation.processing.Messager; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.util.Elements; import javax.tools.Diagnostic; /** * Created by spc on 17/6/6. */ public class AnnotatedClass { private TypeElement mTypeElement;//activity //fragmemt private Elements mElements; private Messager mMessager;//日志打印 public AnnotatedClass(TypeElement typeElement, Elements elements, Messager messager) { mTypeElement = typeElement; mElements = elements; this.mMessager = messager; } public JavaFile generateActivityFile() { // build inject method MethodSpec.Builder injectMethod = MethodSpec.methodBuilder(TypeUtil.METHOD_NAME) .addModifiers(Modifier.PUBLIC) .addParameter(TypeName.get(mTypeElement.asType()), "activity", Modifier.FINAL); injectMethod.addStatement(TypeUtil.MAIN_ACTIVITY_PATH + ".$L.builder()\n.$L($L)\n" + ".$L(new $L(activity))\n" + ".build()\n.$L(activity)", "Dagger" + mTypeElement.getSimpleName() + "$$Component", TypeUtil.APP_Component_Name, TypeUtil.APPCOMPONENT_PROVIDE_PATH, TypeUtil.APP_ActivityModule_Name, TypeUtil.ACTIVITY_MODULE_PATH, TypeUtil.METHOD_NAME); //generaClass TypeSpec injectClass = TypeSpec.classBuilder(mTypeElement.getSimpleName() + "$$InjectActivity") .addModifiers(Modifier.PUBLIC) // .addSuperinterface(ParameterizedTypeName.get(TypeUtil.INJET_NAME, TypeName.get(mTypeElement.asType()))) .addMethod(injectMethod.build()) .build(); String packgeName = mElements.getPackageOf(mTypeElement).getQualifiedName().toString(); return JavaFile.builder(packgeName, injectClass).build(); } public JavaFile generateActivityDaggerFile() { MethodSpec.Builder injectMethod = MethodSpec.methodBuilder(TypeUtil.METHOD_NAME) .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) .addParameter(TypeName.get(mTypeElement.asType()), "activity"); //generaClass TypeSpec injectClass = TypeSpec.interfaceBuilder(mTypeElement.getSimpleName() + "$$Component") .addModifiers(Modifier.PUBLIC) .addAnnotation(TypeUtil.ACTIVITY_SCOPE_CLASSNAME) .addAnnotation(AnnotationSpec.builder(ClassName.get("dagger", "Component")) .addMember("dependencies", "$L", TypeUtil.APP_COMPONENT_PATH + ".class") .addMember("modules", "$L", TypeUtil.ACTIVITY_MODULE_PATH + ".class") .build()) .addMethod(injectMethod.build()) .build(); gradleLog("---->dagger " + mTypeElement.getSimpleName() + " Component buuild success"); String packgeName = mElements.getPackageOf(mTypeElement).getQualifiedName().toString(); return JavaFile.builder(packgeName, injectClass).build(); } public JavaFile generateFragmentFile() { // build inject method MethodSpec.Builder injectMethod = MethodSpec.methodBuilder(TypeUtil.METHOD_NAME) .addModifiers(Modifier.PUBLIC) .addParameter(TypeName.get(mTypeElement.asType()), "fragment", Modifier.FINAL); injectMethod.addStatement(TypeUtil.MAIN_FRAGMENT_PATH + ".$L.builder()\n.$L($L)\n" + ".$L(new $L(fragment))\n" + ".build()\n.$L(fragment)", "Dagger" + mTypeElement.getSimpleName() + "$$Component", TypeUtil.APP_Component_Name, TypeUtil.APPCOMPONENT_PROVIDE_PATH, TypeUtil.APP_FragmentModule_Name, TypeUtil.FRAGMENT_MODULE_PATH, TypeUtil.METHOD_NAME); //generaClass TypeSpec injectClass = TypeSpec.classBuilder(mTypeElement.getSimpleName() + "$$InjectFragment") .addModifiers(Modifier.PUBLIC) .addMethod(injectMethod.build()) .build(); String packgeName = mElements.getPackageOf(mTypeElement).getQualifiedName().toString(); return JavaFile.builder(packgeName, injectClass).build(); } public JavaFile generateFragmentDaggerFile() { MethodSpec.Builder injectMethod = MethodSpec.methodBuilder(TypeUtil.METHOD_NAME) .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) .addParameter(TypeName.get(mTypeElement.asType()), "fragment"); //generaClass TypeSpec injectClass = TypeSpec.interfaceBuilder(mTypeElement.getSimpleName() + "$$Component") .addModifiers(Modifier.PUBLIC) .addAnnotation(TypeUtil.FRAGMENT_SCOPE_CLASSNAME) .addAnnotation(AnnotationSpec.builder(ClassName.get("dagger", "Component")) .addMember("dependencies", "$L", TypeUtil.APP_COMPONENT_PATH + ".class") .addMember("modules", "$L", TypeUtil.FRAGMENT_MODULE_PATH + ".class") .build()) .addMethod(injectMethod.build()) .build(); gradleLog("---->dagger " + mTypeElement.getSimpleName() + " Component buuild success"); String packgeName = mElements.getPackageOf(mTypeElement).getQualifiedName().toString(); return JavaFile.builder(packgeName, injectClass).build(); } private void gradleLog(String msg, Object... args) { mMessager.printMessage(Diagnostic.Kind.NOTE, String.format(msg, args)); } public TypeElement getmTypeElement() { return mTypeElement; } }

还有一个常量文件

public class TypeUtil { /** * ????? */ public static final String MAIN_PROJECT_PACKAGE_NAME = "com.spc.spc.myapplication"; /** * activity ???? */ public static final String MAIN_ACTIVITY_PATH = MAIN_PROJECT_PACKAGE_NAME + ".ui.activity"; public static final String MAIN_FRAGMENT_PATH = MAIN_PROJECT_PACKAGE_NAME + ".ui.fragment"; /** * app???component ???? ???? ?? */ public static final String APP_Component_Name = "appcomponent"; public static final String APP_Component_Name_Capital = "Appcomponent"; public static final String APP_COMPONENT_PATH = MAIN_PROJECT_PACKAGE_NAME + ".di.component." + APP_Component_Name_Capital; /** * activity?Module ???? ???? */ public static final String APP_ActivityModule_Name = "activityModule"; public static final String APP_ActivityModule_Name_Capital = "ActivityModule"; public static final String ACTIVITY_MODULE_PATH = MAIN_PROJECT_PACKAGE_NAME + ".di.module." + APP_ActivityModule_Name_Capital; /** * fragment module */ public static final String APP_FragmentModule_Name = "fragmentModule"; public static final String APP_FragmentModule_Name_Capital = "FragmentModule"; public static final String FRAGMENT_MODULE_PATH = MAIN_PROJECT_PACKAGE_NAME + ".di.module." + APP_FragmentModule_Name_Capital; /** * ??application????App??? Component??? */ public static final String APPCOMPONENT_PROVIDE_PATH = MAIN_PROJECT_PACKAGE_NAME + ".base.MyApplication.getInst().getAppComponent()"; /** * Scope ??? */ public static final ClassName ACTIVITY_SCOPE_CLASSNAME = ClassName.get(MAIN_PROJECT_PACKAGE_NAME + ".di.scope", "ActivityScope"); public static final ClassName FRAGMENT_SCOPE_CLASSNAME = ClassName.get(MAIN_PROJECT_PACKAGE_NAME + ".di.scope", "FragmentScope"); /** * ??????? */ public static final String METHOD_NAME = "inject"; public static final String ANNOTATION_PATH = "com.spc.ActivityInject"; public static final String ANNOTATION_FRAGMENT_PATH = "com.spc.FragmentInject"; // public static final ClassName INJET_NAME = ClassName.get("com.example.injectlib", "Inject"); }

还差最后一个就是注解的初始化代码

package com.spc.spc.myapplication.di.aptinject; import android.support.v4.util.ArrayMap; import android.support.v7.app.AppCompatActivity; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class InjectActivity { private static final ArrayMap<String, Object> injectMap = new ArrayMap<>(); public static void inject(AppCompatActivity activity) { String className = activity.getClass().getName(); try { Object inject = injectMap.get(className); if (inject == null) { Class<?> aClass = Class.forName(className + "$$InjectActivity"); inject = aClass.newInstance(); injectMap.put(className, inject); } Method m1 = inject.getClass().getDeclaredMethod("inject",activity.getClass()); m1.invoke(inject,activity); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }

这样在activity上标注一个@ActivityInject 就可以完成dagger的初始化了。 在baseactivity里面初始化就好

看使用

public abstract class BaseMVPActivity<P extends BasePresenter> extends BaseActivity implements BaseMvpViewInterface { @Inject protected P mvpPresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); InjectActivity.inject(this); mvpPresenter.attachView(this); } @Override protected void onDestroy() { super.onDestroy(); if (mvpPresenter != null) { mvpPresenter.detachView(); } } } @ActivityInject//apt注解注入。不需要手写 public class MainActivity extends BaseMVPActivity<MainPresenter> implements MainacView { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); }

就这样。dagger2不需要component和初始化,一个注解就完成了。 fragment的 一样。在注解处理器里面,处理了fragment的状况

demo地址https://github.com/836154942/dagger2_mvpDemo

转载请注明原文地址: https://www.6miu.com/read-65077.html

最新回复(0)