AndroidAnnotations 源码阅读(1)— 基本原理
发布于:2015-12-01 23:31 最后更新于:2015-12-01 23:31

摘要: AndroidAnnotations 是一个加速开发的开源框架,从名称就可以看出来,它通过提供丰富的注解来简化代码。

使用方式这里不做介绍,官方文档写的非常详细: http://androidannotations.org/。我们的目的是理解这个框架是如何实现的。

1. 框架的组成

在使用 AndroidAnnotations 时,比如我们写了一个这样的 Activity :

@EActivity(R.layout.activity_main)
public class MainActivity extends Activity {

o@ViewById
oTextView textView;
o
o@Override
oprotected void onCreate(Bundle savedInstanceState) {
osuper.onCreate(savedInstanceState);
o}
o
o@AfterViews
opublic void init(){
otextView.setText("Hello world!");
o}

}

如果我们在 AndroidManifest.xml 中使用 注册 MainActivity,编译时将会报错,需要我们将其中的 MainActivity 改为 MainActivity_ 才能通过编译。我们可以在项目目录中找到 MainActivity_ 这个类,这个类的代码如下:

public final class MainActivity_
    extends MainActivity
    implements HasViews, OnViewChangedListener
{

    private final OnViewChangedNotifier onViewChangedNotifier_ = new OnViewChangedNotifier();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        OnViewChangedNotifier previousNotifier = OnViewChangedNotifier.replaceNotifier(onViewChangedNotifier_);
        init_(savedInstanceState);
        super.onCreate(savedInstanceState);
        OnViewChangedNotifier.replaceNotifier(previousNotifier);
        setContentView(layout.activity_main);
    }

    private void init_(Bundle savedInstanceState) {
        OnViewChangedNotifier.registerOnViewChangedListener(this);
    }

    @Override
    public void setContentView(int layoutResID) {
        super.setContentView(layoutResID);
        onViewChangedNotifier_.notifyViewChanged(this);
    }

    @Override
    public void setContentView(View view, LayoutParams params) {
        super.setContentView(view, params);
        onViewChangedNotifier_.notifyViewChanged(this);
    }

    @Override
    public void setContentView(View view) {
        super.setContentView(view);
        onViewChangedNotifier_.notifyViewChanged(this);
    }

    public static MainActivity_.IntentBuilder_ intent(Context context) {
        return new MainActivity_.IntentBuilder_(context);
    }

    @Override
    public void onViewChanged(HasViews hasViews) {
        textView = ((TextView) hasViews.findViewById(id.textView));
        init();
    }

    public static class IntentBuilder_
        extends ActivityIntentBuilder<MainActivity_.IntentBuilder_>
    {


        public IntentBuilder_(Context context) {
            super(context, MainActivity_.class);
        }

        @Override
        public void startForResult(int requestCode) {
            if (context instanceof Activity) {
                Activity activity = ((Activity) context);
                activity.startActivityForResult(intent, requestCode);
            } else {
                context.startActivity(intent);
            }
        }

    }
}

MainActivity_ 在项目编译时生成,这个类才是运行时真正使用的类。它继承自我们编写的 MainActivity 类,同时实现了 HasViews 等接口,这些额外的接口和类来自包 org.androidannotations.api 中。

我们可以看出 AndroidAnnotations 框架可以分为两个部分,一部分负责代码的生成,而另一部分则是作为类库在生成的代码中使用。

在使用 AndroidAnnotations 框架时,我们需要两个 jar 包:androidannotations.jar 和 androidannotations-api.jar。其中,androidannotations.jar 负责生成代码,androidannotations-api.jar 作为类库。

androidannotations-api.jar

目录结构

我们先从 androidannotations-api 开始,这个包的代码目录如下图所示,主要分为 annotations 和 api 两个部分。

api_jar_package.png

annotations 部分定义了各种注解

api_jar_annotations.png

api 部分提供了各种类和接口,在生成的代码中通过继承、组合等方式使用。

api_jar_api.png

androidannotations.jar

androidannotations.jar 在项目编译时使用,它使用了 Annotation Processing Tool(APT)和 JCodeModel 来实现在编译时生成代码。

APT 介绍

APT(Annotation Processing Tool)是一种处理注解的工具,它对源代码文件进行检测找出其中的注解,对这些注解进行额外的处理。 APT 会在编译时自动查找所有继承自 AbstractProcessor 的类,然后调用它们的 process 方法去处理注解。 (包 com.sun.mirror 中 APT 相关的 api 已经废弃,现在使用 javax.annotation.processing 和 javax.lang.model 取代之前的 api )

比如对于这样的注解,

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MethodInfo {
oString author() default "";
}

我们可以使用如下的注解处理器来处理它

@SupportedAnnotationTypes({ "com.mytest.MethodInfo" })
public class MethodInfoProcessor extends AbstractProcessor {

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
        HashMap<String, String> map = new HashMap<String, String>();
        for (TypeElement te : annotations) {
            for (Element element : env.getElementsAnnotatedWith(te)) {
                MethodInfo methodInfo = element.getAnnotation(MethodInfo.class);
                map.put(element.getEnclosingElement().toString(), methodInfo.author());
            }
        }
        return false;
    }
}

更多资料可参考:Java Annotation 及几个常用开源项目注解原理简析

JCodeModel 介绍

JCodeModel 是用于生成 Java 代码的 Java 库,它提供了一种通过 Java 程序来生成 Java 程序的方法。 例如执行以下的代码:

File destDir = new File("src");
JCodeModel codeModel = new JCodeModel();
JDefinedClass clazz = codeModel._class(JMod.PUBLIC, "com.test.Hello", ClassType.CLASS);
JMethod mainMethod = clazz.method(JMod.PUBLIC+JMod.STATIC, codeModel.VOID, "main");
mainMethod.param(codeModel.parseType("String[]"), "args");
mainMethod.body().invoke(codeModel.ref("java.lang.System").staticRef("out"),"println").arg("Hello,world!");
codeModel.build(destDir);

就可以生成如下的类:

public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello,world!");
    }
}

更多资料可参考:用 Java 生成 Java – CodeModel 介绍

目录结构

jar_package.png

  • com.sun.codemodel:只有 JSuperWildcard 一个类,为了解决 CodeModel 无法为“? super X”建模的问题
  • org.androidannotations:包含 AndroidAnnotationProcessor 类(继承自 AbstractProcessor,即上面提到的注解处理器),相当于注解处理程序的入口,控制整个处理流程
  • org.androidannotations.exception:定义异常类型
  • org.androidannotations.generation: 将最终的处理结果(生成的代码)写到文件中
  • org.androidannotations.handler: 与 androidannotations-api.jar 包中的注解对应,对相应的注解进行验证(例如作用于方法上的注解,检查方法参数、返回值等是否符合要求)和处理
  • org.androidannotations.helper: 辅助类,主要在 handler 验证和处理注解时使用(例如判断方法是否为私有、注解中的ResId是否存在,也包含命名方式转换等其他工具类)
  • org.androidannotations.holder: 用于描述和存储代码结构(使用 CodeModel )
  • org.androidannotations.logger: 记录日志
  • org.androidannotations.model: 注解模型以及相关操作(提取注解等)
  • org.androidannotations.process: 控制 handlers 验证和处理注解
  • org.androidannotations.rclass: 与 R.class 相关的操作,包括查找 R.class 、从 R.class 中取值等

2. 通过日志文件查看执行流程

在 MainActivity 的基础上,我们再添加一个 SecondActivity,内部没有任何代码。

@EActivity(R.layout.activity_second)
public class SecondActivity extends Activity {
}

项目编译完成后,我们可以找到 androidannotations.log 日志文件,该文件记录了 androidannotations.jar 包工作的大体流程。

19:19:20.59 [Worker-8] INFO  o.a.AndroidAnnotationProcessor:83 - Initialize AndroidAnnotations 3.3.2 with options {phase=BUILD}  
19:19:20.262 [Worker-8] INFO  o.a.AndroidAnnotationProcessor:107 - Start processing for 3 annotations on 4 elements  
19:19:20.294 [Worker-8] DEBUG o.a.h.AndroidManifestFinder:137 - AndroidManifest.xml file found in parent folder D:\AndroidProjects\AnnotationExample: D:\AndroidProjects\AnnotationExample\AndroidManifest.xml  
19:19:20.340 [Worker-8] INFO  o.a.AndroidAnnotationProcessor:170 - AndroidManifest.xml found: AndroidManifest [applicationPackage=com.annotation.example, componentQualifiedNames=[com.annotation.example.MainActivity_, com.annotation.example.SecondActivity_], permissionQualifiedNames=[], applicationClassName=null, libraryProject=false, debugabble=false, minSdkVersion=8, maxSdkVersion=-1, targetSdkVersion=22]  
19:19:20.356 [Worker-8] INFO  o.a.r.ProjectRClassFinder:50 - Found project R class: com.annotation.example.R  
19:19:20.387 [Worker-8] INFO  o.a.r.AndroidRClassFinder:44 - Found Android class: android.R  
19:19:20.512 [Worker-8] INFO  o.a.p.ModelValidator:42 - Validating elements  
19:19:20.512 [Worker-8] DEBUG o.a.p.ModelValidator:62 - Validating with EActivityHandler: [com.annotation.example.MainActivity, com.annotation.example.SecondActivity]  
19:19:20.528 [Worker-8] DEBUG o.a.p.ModelValidator:62 - Validating with ViewByIdHandler: [textView]  
19:19:20.544 [Worker-8] DEBUG o.a.p.ModelValidator:62 - Validating with AfterViewsHandler: [public void init() ]  
19:19:20.575 [Worker-8] INFO  o.a.p.ModelProcessor:74 - Processing root elements    
19:19:20.575 [Worker-8] DEBUG o.a.p.ModelProcessor:176 - Processing root elements EActivityHandler: [com.annotation.example.MainActivity, com.annotation.example.SecondActivity]  
19:19:20.684 [Worker-8] INFO  o.a.p.ModelProcessor:86 - Processing enclosed elements  
19:19:20.715 [Worker-8] INFO  o.a.AndroidAnnotationProcessor:249 - Number of files generated by AndroidAnnotations: 2  
19:19:20.715 [Worker-8] INFO  o.a.g.ApiCodeGenerator:52 - Writting following API classes in project: []  
19:19:20.731 [Worker-8] DEBUG o.a.g.SourceCodewriter:55 - Generating class: com.annotation.example.MainActivity_  
19:19:20.778 [Worker-8] DEBUG o.a.g.SourceCodewriter:55 - Generating class: com.annotation.example.SecondActivity_  
19:19:20.794 [Worker-8] INFO  o.a.p.TimeStats:81 - Time measurements: [Whole Processing = 532 ms], [Process Annotations = 156 ms], [Find R Classes = 141 ms], [Generate Sources = 79 ms], [Validate Annotations = 47 ms], [Extract Manifest = 46 ms], [Extract Annotations = 16 ms],   
19:19:20.809 [Worker-8] INFO  o.a.AndroidAnnotationProcessor:121 - Finish processing  
评论 登录后评论

没有评论