使用Google开源库AutoService进行组件化开发(1),android多线程面试题

public @interface AutoService {
/** Returns the interface implemented by this service provider. */
Class<?> value();
}

有注解,必须要有对应的注解处理器,AutoServiceProcessor继承AbstractProcessor,一般我们会实现其中的3个方法, 在getSupportedAnnotationTypes中返回了支持的注解类型AutoService.class;getSupportedSourceVersion ,用来指定支持的java版本,一般来说我们都是支持到最新版本,因此直接返回 SourceVersion.latestSupported()即可;主要还是process方法。

public class AutoServiceProcessor extends AbstractProcessor {

@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}

@Override
public Set getSupportedAnnotationTypes() {
return ImmutableSet.of(AutoService.class.getName());
}

@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
try {
return processImpl(annotations, roundEnv);
} catch (Exception e) {
// We don’t allow exceptions of any kind to propagate to the compiler
StringWriter writer = new StringWriter();
e.printStackTrace(new PrintWriter(writer));
fatalError(writer.toString());
return true;
}
}
}

process方法调用processImpl,接着看下这个方法的实现,先看下方法实现,就两个逻辑判断,如果上一次循环中注解处理器已经处理完了,就调用generateConfigFiles生成MEATA_INF配置文件;如果上一轮没有处理就调用processAnnotations处理注解。返回true就代表改变或者生成语法树中的内容;返回false就是没有修改或者生成,通知编译器这个Round中的代码未发生变化。

private boolean processImpl(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (roundEnv.processingOver()) {
generateConfigFiles();
} else {
processAnnotations(annotations, roundEnv);
}

return true;
}

再接着往下看代码之前先看下两个环境变量,RoundEnvironmentProcessingEnvironment

RoundEnvironment提供了访问到当前这个Round中语法树节点的功能,每个语法树节点在这里表示为一个Element,在javax.lang.model包中定义了16类Element,包括常用的元素:包,枚举,类,注解,接口,枚举值,字段,参数,本地变量,异常,方法,构造函数,静态语句块即static{}块,实例语句块即{}块,参数化类型即反省尖括号内的类型,还有未定义的其他语法树节点。

public enum ElementKind {
PACKAGE,
ENUM,
CLASS,
ANNOTATION_TYPE,
INTERFACE,
ENUM_CONSTANT,
FIELD,
PARAMETER,
LOCAL_VARIABLE,
EXCEPTION_PARAMETER,
METHOD,
CONSTRUCTOR,
STATIC_INIT,
INSTANCE_INIT,
TYPE_PARAMETER,
OTHER,
RESOURCE_VARIABLE;

private ElementKind() {
}

public boolean isClass() {
return this == CLASS || this == ENUM;
}

public boolean isInterface() {
return this == INTERFACE || this == ANNOTATION_TYPE;
}

public boolean isField() {
return this == FIELD || this == ENUM_CONSTANT;
}
}

看下RoundEnvironment的源码,errorRaised方法返回上一轮注解处理器是否产生错误;getRootElements返回上一轮注解处理器生成的根元素;最后两个方法返回包含指定注解类型的元素的集合,画重点,这个就是我们自定义注解处理器需要经常打交道的方法。

public interface RoundEnvironment {
boolean processingOver();

boolean errorRaised();

Set<? extends Element> getRootElements();

Set<? extends Element> getElementsAnnotatedWith(TypeElement var1);

Set<? extends Element> getElementsAnnotatedWith(Class<? extends Annotation> var1);
}

另外一个参数ProcessingEnvironment,在注解处理器初始化的时候(init()方法执行的时候)创建,代表了注解处理器框架提供的一个上下文环境,要创建新的代码或者向编译器输出信息或者获取其他工具类等都需要用到这个实例变量。看下它的源码。

  • Messager用来报告错误,警告和其他提示信息;
  • Filer用来创建新的源文件,class文件以及辅助文件;
  • Elements中包含用于操作Element的工具方法;
  • Types中包含用于操作类型TypeMirror的工具方法;

public interface ProcessingEnvironment {
Map<String, String> getOptions();

Messager getMessager();

Filer getFiler();

Elements getElementUtils();

Types getTypeUtils();

SourceVersion getSourceVersion();

Locale getLocale();
}

介绍完一些基础变量后,我们就接着上面先看下processAnnotations方法,方法看起来有点长,但是结构很简单,首先第一步通过RoundEnvironmentgetElementsAnnotatedWith(AutoService.class)拿到所有的标注了AutoService注解的元素。

private void processAnnotations(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {

// 1.
Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(AutoService.class);

log(annotations.toString());
log(elements.toString());

for (Element e : elements) {
// TODO(gak): check for error trees?
// 2.
TypeElement providerImplementer = (TypeElement) e;
// 3.
AnnotationMirror providerAnnotation = getAnnotationMirror(e, AutoService.class).get();
// 4.
DeclaredType providerInterface = getProviderInterface(providerAnnotation);
TypeElement providerType = (TypeElement) providerInterface.asElement();

log("provider interface: " + providerType.getQualifiedName());
log("provider implementer: " + providerImplementer.getQualifiedName());

// 5.
if (!checkImplementer(providerImplementer, providerType)) {
String message = "ServiceProviders must implement their service provider interface. "

  • providerImplementer.getQualifiedName() + " does not implement "
  • providerType.getQualifiedName();
    error(message, e, providerAnnotation);
    }

// 6.
String providerTypeName = getBinaryName(providerType);
String providerImplementerName = getBinaryName(providerImplementer);
log("provider interface binary name: " + providerTypeName);
log("provider implementer binary name: " + providerImplementerName);

providers.put(providerTypeName, providerImplementerName);
}
}

public static Optional getAnnotationMirror(Element element,
Class<? extends Annotation> annotationClass) {
String annotationClassName = annotationClass.getCanonicalName();
for (AnnotationMirror annotationMirror : element.getAnnotationMirrors()) {
TypeElement annotationTypeElement = asType(annotationMirror.getAnnotationType().asElement());
if (annotationTypeElement.getQualifiedName().contentEquals(annotationClassName)) {
return Optional.of(annotationMirror);
}
}
return Optional.absent();
}

AutoService只能作用于非内部非匿名类或者接口,第二步在for循环中强转Element为TypeElement,这个就是被AutoService标注的元素,这里简称为T。接下来这个可能让人容易乱,在前面说过每一个javac是一个循环过程,在第一次扫描到AutoService注解的时候是还没有T的class对象,所以也就不能通过反射来拿到这个注解和注解的参数值value。这个时候第三步就得通过AnnotationMirror,用来表示一个注解,通过它可以拿到注解类型和注解参数。在getAnnotationMirror会判断这个T的注解(通过element.getAnnotationMirrors())名称是不是等于AutoService,相等就返回这个AutoServiceAnnotationMirror

public interface AnnotationMirror {
DeclaredType getAnnotationType();

Map<? extends ExecutableElement, ? extends AnnotationValue> getElementValues();
}

拿到这个注解了,接下来就是要拿到注解的参数value值了,这个在第四步getProviderInterface方法中完成。

private DeclaredType getProviderInterface(AnnotationMirror providerAnnotation) {

Map<? extends ExecutableElement, ? extends AnnotationValue> valueIndex =
providerAnnotation.getElementValues();
log("annotation values: " + valueIndex);

AnnotationValue value = valueIndex.values().iterator().next();
return (DeclaredType) value.getValue();
}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

最后

针对Android程序员,我这边给大家整理了一些资料,包括不限于高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!

往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、混合式开发(ReactNative+Weex)全方面的Android进阶实践技术,群内还有技术大牛一起讨论交流解决问题。

践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!**

往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、混合式开发(ReactNative+Weex)全方面的Android进阶实践技术,群内还有技术大牛一起讨论交流解决问题。

[外链图片转存中…(img-LNJCWaws-1711824830614)]

[外链图片转存中…(img-RNIEYgya-1711824830614)]

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

  • 27
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值