相关文档
注解分析
-
注解知识回顾
-
创建自定义注解@interface;
-
创建并注册注解处理器AbstractProcessor
-
实现AbstractProcessor的回调
-
继承AbstractProcessor,需要重写process()方法,这里是处理注解内部逻辑的,也是本文的关键点之一;
-
此外还需要实现几个简单的方法init ()、getSupportedSourceVersion()、getSupportedAnnotationTypes()
-
getSupportedSourceVersion():设置支持的版本,一般用最新的就好;
-
getSupportedAnnotationTypes():添加支持的注解类型,可以是单个/多个,用Set存储;
-
init ():一些初始化操作,获取一些有用的系统工具类,比如生成文件、打印信息、处理元素等;
-
getSupportedSourceVersion()、getSupportedAnnotationTypes()这2个方法还有一种简单的方式来实现,如下:
-
@AutoService(Processor.class) @SupportedAnnotationTypes({"com.zx.annotation"}) @SupportedSourceVersion(SourceVersion.RELEASE_8) public class ViewInjectProcessor extends AbstractProcessor {}
-
是通过注解来实现的,看上去是比较简洁
-
@SupportedAnnotationTypes()可以申明一个注解数组,但是这种字符串拼接容易出错;
-
@SupportedSourceVersion:设置支持的源码版本,可以是RELEASE_0~RELEASE_8,但是不能使用latestSupported()设置最新的版本;
-
-
Epoxy自定义注解
自定义注解位于epoxy/epoxy-annotations模块里
Epoxy注解处理器
注解器位于epoxy/epoxy-processor模块中,模块里有多个注解器,各注解器的关系如下
-
最上层的父类BaseProcessor:主要做了基础封装,比如处理器可处理的类型通过实现com.airbnb.epoxy.processor.BaseProcessor#supportedAnnotations方法来获取
-
com.airbnb.epoxy.processor.DataBindingProcessor:用于处理
这两个注解。
-
com.airbnb.epoxy.processor.BaseProcessorWithPackageConfigs:这是一个抽象的processor.这个抽象process用于处理
-
我们先简单看下这两个注解
-
PackageEpoxyConfig:
-
做一些全局配置的事,比如生成Model类的前裰,或者默认布局的匹配规则
-
官方说明:
-
Annotation Type in com.airbnb.epoxy
-
Use this annotation on any class in your package to specify default behavior for the Epoxy annotation processor for that package.
-
-
-
PackageModelViewConfig:
-
这个看上去和PackageEpoxyConfig没啥区别,主要还是用途不一样吧
-
官方说明:
-
Annotation Type in com.airbnb.epoxy
-
Settings that apply to all views annotated with ModelView in this package.
-
-
-
-
-
com.airbnb.epoxy.processor.ControllerProcessor:BaseProcessorWithPackageConfigs的子类,只处理一个注解:
-
AutoModel:
-
对于表示静态内容的模型(例如标题或加载器),可以将AutoModel注解与EpoxyController一起使用,以自动为您生成唯一的ID。
-
Annotation Type in com.airbnb.epoxy
-
Used to annotate model fields in an EpoxyController.
-
-
-
com.airbnb.epoxy.processor.EpoxyProcessor:BaseProcessorWithPackageConfigs的子类,用于处理如下两个注解:
-
EpoxyModelClass
-
创建model类的注解,用于viewholder类创建model方式
-
-
EpoxyAttribute
- 在EpoxyModelClass 指定的类里使用,用于声明属性
-
-
com.airbnb.epoxy.processor.ModelViewProcessor:BaseProcessorWithPackageConfigs的子类,用来处理如下三个注解:
-
ModelView:
-
与EpoxyModelClass类似,用于生成model的。用于自定义view创建model方式
-
An annotation on custom view classes to automatically generate an EpoxyModel for that view. Used in conjunction with ModelProp
-
-
TextProp:
-
与ModelView配套使用定义属性用的
-
-
CallbackProp:
- 与ModelView配套使用定义属性用的
-
EpoxyProcessor分析
上面提到,EpoxyProcessor用于处理viewholder生成model的过程。
通过BaseProcess封装后,原有的process功能通过com.airbnb.epoxy.processor.BaseProcessor#processRound 来实现,子类实现该方法.该方法流程如下:
流程图中函数分析
- com.airbnb.epoxy.processor.EpoxyProcessor#getOrCreateTargetClass流程如下:
- writeModel流程如下
processRound结束后,回到com.airbnb.epoxy.processor.BaseProcessor#processRoundInternal
在这里接着会生成Epoxy${processorName.removePrefix("Epoxy")}KotlinExtensions
文件。
if (!configManager.disableKotlinExtensionGeneration()) {
// TODO: Potentially generate a single file per model to allow for an isolating processor
kotlinExtensionWriter.generateExtensionsForModels(
generatedModels,
processorName
)
timer.markStepCompleted("generateKotlinExtensions")
}
疑难代码分析
-
superClassElement.type.typeArguments
- 得到的是类的泛型值,比如abstract class TestModel2<View> ,View即是该值
产生文件分析
XXX_
通过EpoxyAttribute注解生成该注解所在类的子类。也就是model真实类
XXXBuilder
这是一个接口,XXX_会实现该接口。该接口是用于辅助创建XXX_对象的。
Epoxy${processorName.removePrefix("Epoxy")}KotlinExtensions
这是一个工具类,用于创建XXX_对象用的
ControllerProcessor分析
该processor只处理AutoModel注解。该注解用于自动生成model对象,而不是开发者自己创建
该注解用于创建GENERATED_HELPER_CLASS_SUFFIX**类。
GENERATED_HELPER_CLASS_SUFFIX* 为_EpoxyHelper*
className为注解所在类
生成的类为ControllerHelper子类。在生成的类里会创建被AutoModel注解的对象
ModelViewProcessor分析
先来看下Processor处理流程
各注解作用:
-
ModelView
-
该注解用于自定义view.用于创建model
-
autoLayout
- 当设置了这个值后,会在生成model类的时候,多生成一些设置view的属性代码,比如在buildView里增加:setLayoutParams,属性转代码对应关系如下:
-
-
ModelProp
- 在自定义view中的settter使用该注解定义model属性
-
TextProp
- view的属性,区别于ModelProp。只能用于调用参数为CharSequence 的属性
-
CallbackProp
- 同样是view属性,作为一个callback.
-
OnViewRecycled
- 当view被回收时,修饰的方法将会被调用
-
OnVisibilityChanged
- 当view可见区域变化时,OnVisibilityChanged修饰的方法会被调用
-
OnVisibilityStateChanged
- 当view可见状态的属性变化时,OnVisibilityStateChanged修饰的方法会被调用
-
AfterPropsSet
- 当view的所有属性都被设置后,AfterPropsSet修饰的属性会被调用
源码分析
分析之前我们先来复习一下如何实现一个最简单的recyclerview:
-
实现Recyclerview的Adapter
-
实现public abstract VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType); 返回创建的viewholder实例
-
实现public abstract void onBindViewHolder(@NonNull VH holder, int position);将viewholder与数据绑定
-
-
将adapter与recyclerview绑定
-
设置recyclerview的的layoutmanager
我们再来看看Epoxy如何实现一个简单的列表:
-
用注解定义model。
-
创建EpoxyController的子类
-
在EpoxyController子类的protected abstract void buildModels(T data); 里添加model.
我们知道Epoxy内部也是基于Recyclerview来实现的。我们从EpoxyController为作入口来分析,找出从EpoxyController到Adapter.onCreateViewHolder的过程:
该类中有个对象:private final EpoxyControllerAdapter adapter;类结构如下:
其父类BaseEpoxyAdapter 继承自RecyclerView.Adapter。我们先看下onCreateViewHolder的实现
@Override
public EpoxyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
EpoxyModel<?> model = viewTypeManager.getModelForViewType(this, viewType);
View view = model.buildView(parent);
return new EpoxyViewHolder(parent, view, model.shouldSaveViewState());
}
可以看出model是从viewTypeManager.getModelForViewType里获取的。这里的viewType如果在recyclerview里,是需要开发者自己定义的。在epoxy里,直接取布局的int值:
protected int getDefaultLayout() {
return R.layout.button;
}
com.airbnb.epoxy.ViewTypeManager#getModelForViewType的实现如下:
EpoxyModel<?> getModelForViewType(BaseEpoxyAdapter adapter, int viewType) {
if (lastModelForViewTypeLookup != null
&& getViewType(lastModelForViewTypeLookup) == viewType) {
// We expect this to be a hit 100% of the time
return lastModelForViewTypeLookup;
}
adapter.onExceptionSwallowed(
new IllegalStateException("Last model did not match expected view type"));
// To be extra safe in case RecyclerView implementation details change...
for (EpoxyModel<?> model : adapter.getCurrentModels()) {
if (getViewType(model) == viewType) {
return model;
}
}
// Check for the hidden model.
HiddenEpoxyModel hiddenEpoxyModel = new HiddenEpoxyModel();
if (viewType == hiddenEpoxyModel.getViewType()) {
return hiddenEpoxyModel;
}
throw new IllegalStateException("Could not find model for view type: " + viewType);
}
adapter.getCurrentModels()的实现:这是一个抽象类,其实现为com.airbnb.epoxy.EpoxyControllerAdapter#getCurrentModels:
List<? extends EpoxyModel<?>> getCurrentModels() {
return differ.getCurrentList();
}
值来源于:
private synchronized boolean tryLatchList(@Nullable List<? extends EpoxyModel<?>> newList,
int runGeneration) {
if (generationTracker.finishGeneration(runGeneration)) {
list = newList;
if (newList == null) {
readOnlyList = Collections.emptyList();
} else {
readOnlyList = Collections.unmodifiableList(newList);
}
return true;
}
return false;
}
tryLatchList由com.airbnb.epoxy.AsyncEpoxyDiffer#onRunCompleted调用 的。继续往前看首次是由com.airbnb.epoxy.EpoxyController#requestModelBuild发起。此方法由用户发起。