您的位置:首页 > 移动开发 > Android开发

Android APT开发教程 五 使用注释完成findViewById和setConten

2018-01-30 19:43 501 查看
github项目代码地址

https://github.com/979451341/TestAPT

之前我们做了一个能够给int赋值的apt,这个时候我想到好像控件类似TextView的id值也是int类型,所以我也可以给控件id赋值

不过有一个问题就是如何去分辨哪个是int类型,哪个是控件的id
但是我们可以去试一下获取这两种元素的信息有何不同

比如我这样一弄,就可以打印出类似Element类似分类的属性

@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(TestActivity.class);
for (Element element : elements) {
// 判断是否Class
TypeElement typeElement = (TypeElement) element;
List<? extends Element> members = elementUtils.getAllMembers(typeElement);
TestActivity activity = typeElement.getAnnotation(TestActivity.class);
MethodSpec.Builder bindViewMethodSpecBuilder = MethodSpec.methodBuilder("setDefualt")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(TypeName.VOID)
.addParameter(ClassName.get(typeElement.asType()), "activity");

for (Element item : members) {
TestInt diView = item.getAnnotation(TestInt.class);

if (diView == null){
continue;
}

bindViewMethodSpecBuilder.addStatement(String.format("%s  %s",item.getKind(),item.asType().getKind()));
}
TypeSpec typeSpec = TypeSpec.classBuilder("Test" + element.getSimpleName())
.superclass(TypeName.get(typeElement.asType()))
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addMethod(bindViewMethodSpecBuilder.build())
.build();
JavaFile javaFile = JavaFile.builder(getPackageName(typeElement), typeSpec).build();
try {
javaFile.writeTo(processingEnv.getFiler());
} catch (IOException e) {
e.printStackTrace();
}
}
return true;
}

结果如下

public final class TestMainActivity extends MainActivity {
public static void setDefualt(MainActivity activity) {

FIELD  INT;
FIELD  INT;
FIELD  INT;
FIELD  DECLARED;

}
}

可以看到item.asType().getKind()能够分辨控件id和int类型的区别,
我把加代码的那段换成如下,就是判断如果类型为INT就正常int赋值,如果类型为DECLARED就findViewById

if(item.asType().getKind() == INT)
bindViewMethodSpecBuilder.addStatement(String.format("activity.%s = %s",item.getSimpleName(),diView.value()));
if(item.asType().getKind() == DECLARED)
bindViewMethodSpecBuilder.addStatement(String.format("activity.%s = (%s)activity.findViewById(%s)",item.getSimpleName(),item.asType().toString(),diView.value()));

后来通过实验,代码运行正常,

@TestActivity
public class MainActivity extends Activity {

@TestInt
int a;
@TestInt(value = 1)
int b;
@TestInt(1)
int c;
@TestInt(R.id.tv1)
TextView tv1;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TestMainActivity.setDefualt(this);
setContentView(R.layout.activity_main);

Log.v("zzw"," a:"+a+" b:"+b+" c:"+c);
tv1.setText(" a:"+a+" b:"+b+" c:"+c);
}

}

但是我还记得R.layout.activity_main也是int类型,我们应该能够使用注解来设置布局,这注解用在哪呢,我就用在TestActivity这个注解吧

那我就要改变TestActivity的代码,加个int的变量

@Target(ElementType.TYPE)[url=mailto:br/>@Retention(RetentionPolicy.CLASS)
@Retention(RetentionPolicy.CLASS)
int value() default 0;
}

然后在注解处理器里添加一行接收TestActivity的value值并给Activity设置布局的代码

TestActivity activity = typeElement.getAnnotation(TestActivity.class);

if(activity == null){
continue;
}
bindViewMethodSpecBuilder.addStatement(String.format("activity.setContentView(%s)",activity.value()));

使用如下:

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

@TestInt
int a;
@TestInt(value = 1)
int b;
@TestInt(1)
int c;
@TestInt(R.id.tv1)
TextView tv1;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TestMainActivity.setDefualt(this);

Log.v("zzw"," a:"+a+" b:"+b+" c:"+c);
tv1.setText(" a:"+a+" b:"+b+" c:"+c);
}

}

完整的注释处理器代码如下

@AutoService(Processor.class)
public class TestProcessor extends AbstractProcessor {
private Elements elementUtils;[url=mailto:br/>@Override
@Override
// 规定需要处理的注解
return Collections.singleton(TestActivity.class.getCanonicalName());[url=mailto:br/>}
@Override
}
@Override
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  APT