dagger2结合apt自动生成注入代码搭建mvp
来源:互联网 发布:海森伯格矩阵的用途 编辑:程序博客网 时间:2024/06/14 03:58
大家使用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
阅读全文
0 0
- dagger2结合apt自动生成注入代码搭建mvp
- Dagger2和MVP的结合
- Dagger2的自动代码生成问题
- android dagger2搭建mvp架构
- Dagger2-深入三(mvp结合使用)
- android apt编译时期自动生成代码
- Dagger2生成代码解析
- Dagger2 生成代码学习
- Rxjava + retrofit + dagger2 + mvp搭建Android框架
- dagger2+butterknife+xutils搭建MVP模型
- RxJava2 + Retrofit2 + Mvp + Dagger2框架搭建
- kotlin结合dagger2使用为什么在编译时无法自动生成DaggerxxxComponent类
- Android Mvp快速搭建框架MVP+Dagger2+Retrofit+Rxjava
- Dagger2+MVP
- Dagger2+mvp
- android之dagger2+rxjava+retrofit2+mvp架构的结合
- 使用APT减少MVP的冗余代码
- android MVP + dagger2 + Retrofit + Rxjava+okhttp android基础项目框架搭建(1)--之Dagger2引入
- spring中各jar功能及jar包之间的依赖关系
- 第一天学 Kotlin
- 硬盘的那些事(主分区、扩展分区、逻辑分区、活动分区、系统分区、启动分区、引导扇区、MBR等)
- struts2的java.lang.NoSuchMethodException异常处理
- shell流程中for、while、until介绍
- dagger2结合apt自动生成注入代码搭建mvp
- Linux crontab定时执行任务 命令格式与详细例子
- android面试集锦总结二
- linux logrotate备份日志
- Linux-鸟菜-6-文件与目录管理
- Linux DNS查看以及dig命令使用
- flume事务解析
- 常用文本控件
- HTML5 本地存储 localStorage、sessionStorage 的遍历、存储大小限制处理