开发者( KaiFaX ) 面向开发者、程序员的专业平台! 与Python相比,Java是一门比较严肃的语言
作为一个先学Python的程序员,做起Android难免会觉得不舒服,有些死板,非常怀念decorator等方便的方法
为了实现一个简单的逻辑,你可能需要写很多额外的代码
举个例子,怎么从一个 Cursor 里取出类型为 ClassA 的实例到 List ? 1. 找出 ClassA 对应所有的列和每列在 Cursor 对应的索引
int columnIndex = cursor.getColumnIndex("columnA"); 2. 如果索引存在,根据类型取出正确的值
if (columnIndex >= 0) { instance.columnA = cursor.getString(columnIndex); } 3. 对于每个属性,不断重复上述步骤取出对应的值
这么做的问题在哪? * 重复代码 * 重复代码 * 无聊 * 容易出错,不好维护 反射 我就是不想写那么多无聊的代码,怎么办?要不试试范型/反射
1. 取出所有的属性
Arrays.asList(cls.getDeclaredFields()) 2. 循环属性队列
3. 把属性设置成accessible
field.setAccessible(true); 4. 找到索引
int columnIndex = cursor.getColumnIndex(fieldName); if (columnIndex < 0) { continue; } 5. 取出属性的类型,根据类型从 Cursor 里取出正确的值
Class fieldType = field.getType(); if (fieldType.equals(int.class)) { field.setInt(instance, cursor.getInt(columnIndex)); } else { // more type check 6. 结束循环
这样我们就不用很无聊的把同样的逻辑对于每种类型写一遍又一遍
Processor 用了反射后,也会有一些其他问题,这样的代码可读性不是太好,不是很容易调试
既然我们可以通过反射实现这些逻辑,为什么不干脆通过反射把这部分代码直接生成出来呢? 1. 定义你要处理的annotation
2. 定义你的 Processor 类,继承 AbstractProcessor
@AutoService(Processor.class) @SupportedSourceVersion(SourceVersion.RELEASE_7) @SupportedAnnotationTypes("com.glow.android.Annotation") public class MyProcessor extends AbstractProcessor { 3. 创建要生成的方法
ClassName currentType = ClassName.get(element); MethodSpec.Builder builder = MethodSpec.methodBuilder("fromCursor") .returns(currentType) .addModifiers(Modifier.STATIC) .addModifiers(Modifier.PUBLIC) .addParameter(ClassName.get("android.database", "Cursor"), "cursor"); 4. 循环取出每一列,并像下面这样生成代码
CodeBlock.Builder blockBuilder = CodeBlock.builder(); blockBuilder.beginControlFlow(""); blockBuilder.addStatement("int columnIndex = cursor.getColumnIndex($S)", column); blockBuilder.beginControlFlow("if (columnIndex >= 0)"); ColumnType columnType = columnTypeMap.get(column); String cursorType = null; if (columnType == ColumnType.INT) { cursorType = "Int"; } else if (columnType == ColumnType.LONG) { cursorType = "Long"; } else if (columnType == ColumnType.FLOAT) { cursorType = "Float"; } else if (columnType == ColumnType.STRING) { cursorType = "String"; } else { abort("Unsupported type", element); } 5. 把代码输出到编译时的文件里
JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile( concatClassName(packageName, className), element); Writer writer = sourceFile.openWriter(); javaFile.writeTo(writer); writer.close(); 6. 用 apt 工具把我们上面写的库加到编译过程去
Tips: * 用 AutoService 可以方便的生成 Processor 方法 * 强推 Javapoet ,用来生成漂亮的代码 AOP AOP的做法和Processor类似,这里就不详述