编译时注解Butterknife源码解析之深入篇刘永雷Word文件下载.docx

上传人:b****8 文档编号:22668513 上传时间:2023-02-05 格式:DOCX 页数:31 大小:32.36KB
下载 相关 举报
编译时注解Butterknife源码解析之深入篇刘永雷Word文件下载.docx_第1页
第1页 / 共31页
编译时注解Butterknife源码解析之深入篇刘永雷Word文件下载.docx_第2页
第2页 / 共31页
编译时注解Butterknife源码解析之深入篇刘永雷Word文件下载.docx_第3页
第3页 / 共31页
编译时注解Butterknife源码解析之深入篇刘永雷Word文件下载.docx_第4页
第4页 / 共31页
编译时注解Butterknife源码解析之深入篇刘永雷Word文件下载.docx_第5页
第5页 / 共31页
点击查看更多>>
下载资源
资源描述

编译时注解Butterknife源码解析之深入篇刘永雷Word文件下载.docx

《编译时注解Butterknife源码解析之深入篇刘永雷Word文件下载.docx》由会员分享,可在线阅读,更多相关《编译时注解Butterknife源码解析之深入篇刘永雷Word文件下载.docx(31页珍藏版)》请在冰豆网上搜索。

编译时注解Butterknife源码解析之深入篇刘永雷Word文件下载.docx

*/

for(Elementelement:

env.getElementsAnnotatedWith(BindView.class)){

//wedon'

tSuperficialValidation.validateElement(element)

//sothatanunresolvedViewtypecanbegeneratedbylaterprocessingrounds

try{

parseBindView(element,builderMap,erasedTargetNames);

}catch(Exceptione){

logParsingError(element,BindView.class,e);

}

}

很简单,获取了项目中所有的被@BindView注解了的Element,通过for()循环处理每一个,一个try{}catch{}代码块,try中出问题,打印信息,关于在注解处理器中处理错误log信息,在这里就不讲了,可以在init()方法中获取Messager辅助类。

看来重点在parseBindView(element,builderMap,erasedTargetNames);

方法中了,跟进去:

privatevoidparseBindView(Elementelement,Map<

TypeElement,BindingSet.Builder>

builderMap,

Set<

TypeElement>

erasedTargetNames){

//获取父级Element;

TypeElementenclosingElement=(TypeElement)element.getEnclosingElement();

//Startbyverifyingcommongeneratedcoderestrictions.

booleanhasError=isInaccessibleViaGeneratedCode(BindView.class,"

fields"

element)

||isBindingInWrongPackage(BindView.class,element);

//VerifythatthetargettypeextendsfromView.

TypeMirrorelementType=element.asType();

if(elementType.getKind()==TypeKind.TYPEVAR){

TypeVariabletypeVariable=(TypeVariable)elementType;

elementType=typeVariable.getUpperBound();

NamequalifiedName=enclosingElement.getQualifiedName();

NamesimpleName=element.getSimpleName();

//@BindView必须作用在View上或者interface上;

if(!

isSubtypeOfType(elementType,VIEW_TYPE)&

&

!

isInterface(elementType)){

if(elementType.getKind()==TypeKind.ERROR){

note(element,"

@%sfieldwithunresolvedtype(%s)"

+"

mustelsewherebegeneratedasaVieworinterface.(%s.%s)"

BindView.class.getSimpleName(),elementType,qualifiedName,simpleName);

}else{

error(element,"

@%sfieldsmustextendfromVieworbeaninterface.(%s.%s)"

BindView.class.getSimpleName(),qualifiedName,simpleName);

hasError=true;

if(hasError){

return;

//Assembleinformationonthefield.

intid=element.getAnnotation(BindView.class).value();

//通过enclosingElement获取builder,每一个builder对应一个类,如activity;

BindingSet.Builderbuilder=builderMap.get(enclosingElement);

//将element所在包与id封装到QualifiedId中;

QualifiedIdqualifiedId=elementToQualifiedId(element,id);

if(builder!

=null){

//判断当前@BindView所修饰控件是否已经绑定过;

//getId():

将id存入Id对象,并存入symbols;

StringexistingBindingName=builder.findExistingBindingName(getId(qualifiedId));

if(existingBindingName!

Attempttouse@%sforanalreadyboundID%don'

%s'

.(%s.%s)"

BindView.class.getSimpleName(),id,existingBindingName,

enclosingElement.getQualifiedName(),element.getSimpleName());

//新建一个builder;

builder=getOrCreateBindingBuilder(builderMap,enclosingElement);

Stringname=simpleName.toString();

TypeNametype=TypeName.get(elementType);

//判断是否添加了@Nullable

booleanrequired=isFieldRequired(element);

//通过Id创建ViewBinding.Builder并setFieldBinding(fieldViewBinding)

builder.addField(getId(qualifiedId),newFieldViewBinding(name,type,required));

//Addthetype-erasedversiontothevalidbindingtargetsset.

erasedTargetNames.add(enclosingElement);

方法也还好,不到100行,来看看在这个方法中做了一些什么操作吧。

咱们先拿出一部分来看:

NamequalifiedName=enclosingElement.getQualifiedName();

NamesimpleName=element.getSimpleName();

这部分是对我们@BindView注解应用的一个正确性的一个检查,首先获取了我们的element对应的外部类的TypeElement,比如,activity中用@BindView注解了一个Buttonbtn;

获取了activity对应的TypeElement,如果你看了上篇文章你就会明白。

然后调用了一个isInaccessibleViaGeneratedCode(BindView.class,"

element)方法与一个isBindingInWrongPackage(BindView.class,element)方法进行判断操作。

一个一个来看一下,第一个:

*检查annotation作用域是否正确;

*

*@paramannotationClass

*@paramtargetThing

*@paramelement

*@return

*/

privatebooleanisInaccessibleViaGeneratedCode(Class<

?

extendsAnnotation>

annotationClass,

StringtargetThing,Elementelement){

booleanhasError=false;

//获取当前element所在类的TypeElement;

//Verifymethodmodifiers.获取当前element的修饰符;

Set<

Modifier>

modifiers=element.getModifiers();

//修饰符不能是private或者static的,否则报告异常(error方法);

//Messager提供给注解处理器一个报告错误、警告以及提示信息的途径。

//它不是注解处理器开发者的日志工具,而是用来写一些信息给使用此注解器的第三方开发者的。

if(modifiers.contains(PRIVATE)||modifiers.contains(STATIC)){

@%s%smustnotbeprivateorstatic.(%s.%s)"

annotationClass.getSimpleName(),targetThing,enclosingElement.getQualifiedName(),

element.getSimpleName());

//Verifycontainingtype.element只能直接从属于类(不能修饰局部变量);

否则报错;

if(enclosingElement.getKind()!

=CLASS){

error(enclosingElement,"

@%s%smayonlybecontainedinclasses.(%s.%s)"

//Verifycontainingclassvisibilityisnotprivate.element外层类不能是私有的,否则报错;

if(enclosingElement.getModifiers().contains(PRIVATE)){

@%s%smaynotbecontainedinprivateclasses.(%s.%s)"

returnhasError;

在这个类中判断了三种非正常情况:

1.@BindView注解的Element为private或者static修饰报错,如下例子:

@BindView(R.id.btn)

privateButtonbtn;

这种情况下就会报错。

2.当前Element不是直接在一个类里边,报错。

在一个方法的局部变量上添加了注解。

3.外部Element是private的报错。

privateclassActivityextends...{

@BindView(R.id.btn)

再看一下isBindingInWrongPackage(BindView.class,element)方法:

*检查anitation注解是否作用在了系统类上;

privatebooleanisBindingInWrongPackage(Class<

Elementelement){

TypeElementenclosingElement=(TypeElement)element.getEnclosingElement();

StringqualifiedName=enclosingElement.getQualifiedName().toString();

//不能作用于Android系统类里;

if(qualifiedName.startsWith("

android."

)){

@%s-annotatedclassincorrectlyinAndroidframeworkpackage.(%s)"

annotationClass.getSimpleName(),qualifiedName);

returntrue;

//不能作用在java系统类中;

java."

@%s-annotatedclassincorrectlyinJavaframeworkpackage.(%s)"

returnfalse;

这个方法主要是检查我们是否用到了系统类上,这里注意我们自己定义的包名。

接着回到上一个方法向下看,后续又检查了是否用在了View子类上或者Interface上。

我都加了注释,不在详细解释。

如果上边检查有一步出问题,则return终止。

到这里,检查我们应用@BindView合法性就完了。

再往下边走:

//getId():

}else{

首先获取到我们注解中指定的id,如下代码中的R.id.btn:

Buttonbtn;

查看builderMap中是否已经缓存了外部Element对应的BindingSet.Builder,通过id创建QualifiedId,看一下这个过程:

privateQualifiedIdelementToQualifiedId(Elementelement,intid){

returnnewQualifiedId(elementUtils.getPackageOf(element).getQualifiedName().toString(),id);

这里用到了辅助类elementUtils获取element的包名,通过包名与id创建了QualifiedId

后边是builder判断,如果不为空,通过QualifiedId生成Id判断是否注解过相同id,注解过,则输出错误信息。

Builder为空,调用getOrCreateBindingBuilder(builderMap,enclosingElement)创建或获取builder,看一下:

privateBindingSet.BuildergetOrCreateBindingBuilder(

Map<

builderMap,TypeElementenclosingElement){

BindingSet.Builderbuilder=builderMap.get(enclosingElement);

if(builder==null){

//生成一个builder,

//builder中保存了泛型信息、将要生成的类名称、是否Final修饰、是否View内部,是否Activity内部、是否Dialog内部;

builder=BindingSet.newB

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 农学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1