摘要: 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 中使用
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 两个部分。
annotations 部分定义了各种注解
api 部分提供了各种类和接口,在生成的代码中通过继承、组合等方式使用。
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 介绍
目录结构
- 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
没有评论