Epoxy源码分析

981 阅读5分钟

相关文档

www.jianshu.com/p/cc369dca2…

注解分析

  • 注解知识回顾

    1. 创建自定义注解@interface;

    2. 创建并注册注解处理器AbstractProcessor

    3. 实现AbstractProcessor的回调

      1. 继承AbstractProcessor,需要重写process()方法,这里是处理注解内部逻辑的,也是本文的关键点之一;

      2. 此外还需要实现几个简单的方法init ()、getSupportedSourceVersion()、getSupportedAnnotationTypes()

      3. getSupportedSourceVersion():设置支持的版本,一般用最新的就好;

      4. getSupportedAnnotationTypes():添加支持的注解类型,可以是单个/多个,用Set存储;

      5. init ():一些初始化操作,获取一些有用的系统工具类,比如生成文件、打印信息、处理元素等;

      6. getSupportedSourceVersion()、getSupportedAnnotationTypes()这2个方法还有一种简单的方式来实现,如下:

      7. @AutoService(Processor.class) @SupportedAnnotationTypes({"com.zx.annotation"}) @SupportedSourceVersion(SourceVersion.RELEASE_8) public class ViewInjectProcessor extends AbstractProcessor {}

      8. 是通过注解来实现的,看上去是比较简洁

      9. @SupportedAnnotationTypes()可以申明一个注解数组,但是这种字符串拼接容易出错;

      10. @SupportedSourceVersion:设置支持的源码版本,可以是RELEASE_0~RELEASE_8,但是不能使用latestSupported()设置最新的版本;

Epoxy自定义注解

自定义注解位于epoxy/epoxy-annotations模块里

image

Epoxy注解处理器

注解器位于epoxy/epoxy-processor模块中,模块里有多个注解器,各注解器的关系如下

image

  1. 最上层的父类BaseProcessor:主要做了基础封装,比如处理器可处理的类型通过实现com.airbnb.epoxy.processor.BaseProcessor#supportedAnnotations方法来获取

  2. com.airbnb.epoxy.processor.DataBindingProcessor:用于处理

这两个注解。

  1. com.airbnb.epoxy.processor.BaseProcessorWithPackageConfigs:这是一个抽象的processor.这个抽象process用于处理

    1. 我们先简单看下这两个注解

      1. PackageEpoxyConfig:

        1. 做一些全局配置的事,比如生成Model类的前裰,或者默认布局的匹配规则

        2. 官方说明:

          1. Annotation Type in com.airbnb.epoxy

          2. Use this annotation on any class in your package to specify default behavior for the Epoxy annotation processor for that package.

      2. PackageModelViewConfig:

        1. 这个看上去和PackageEpoxyConfig没啥区别,主要还是用途不一样吧

        2. 官方说明:

          1. Annotation Type in com.airbnb.epoxy

          2. Settings that apply to all views annotated with ModelView in this package.

  2. com.airbnb.epoxy.processor.ControllerProcessor:BaseProcessorWithPackageConfigs的子类,只处理一个注解:

    1. AutoModel:

      1. 对于表示静态内容的模型(例如标题或加载器),可以将AutoModel注解与EpoxyController一起使用,以自动为您生成唯一的ID。

      2. Annotation Type in com.airbnb.epoxy

      3. Used to annotate model fields in an EpoxyController.

  3. com.airbnb.epoxy.processor.EpoxyProcessor:BaseProcessorWithPackageConfigs的子类,用于处理如下两个注解:

    1. EpoxyModelClass

      1. 创建model类的注解,用于viewholder类创建model方式

    2. EpoxyAttribute

      1. 在EpoxyModelClass 指定的类里使用,用于声明属性
  4. com.airbnb.epoxy.processor.ModelViewProcessor:BaseProcessorWithPackageConfigs的子类,用来处理如下三个注解:

    1. ModelView:

      1. 与EpoxyModelClass类似,用于生成model的。用于自定义view创建model方式

      2. An annotation on custom view classes to automatically generate an EpoxyModel for that view. Used in conjunction with ModelProp

    2. TextProp:

      1. 与ModelView配套使用定义属性用的

    3. CallbackProp:

      1. 与ModelView配套使用定义属性用的

EpoxyProcessor分析

上面提到,EpoxyProcessor用于处理viewholder生成model的过程。

通过BaseProcess封装后,原有的process功能通过com.airbnb.epoxy.processor.BaseProcessor#processRound 来实现,子类实现该方法.该方法流程如下:

流程图中函数分析

  1. com.airbnb.epoxy.processor.EpoxyProcessor#getOrCreateTargetClass流程如下:
  1. 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")
}

疑难代码分析

  1. superClassElement.type.typeArguments

    1. 得到的是类的泛型值,比如abstract class TestModel2<View> ,View即是该值

产生文件分析

XXX_

通过EpoxyAttribute注解生成该注解所在类的子类。也就是model真实类

XXXBuilder

这是一个接口,XXX_会实现该接口。该接口是用于辅助创建XXX_对象的。

Epoxy${processorName.removePrefix("Epoxy")}KotlinExtensions

这是一个工具类,用于创建XXX_对象用的

ControllerProcessor分析

该processor只处理AutoModel注解。该注解用于自动生成model对象,而不是开发者自己创建

该注解用于创建classNameclassNameGENERATED_HELPER_CLASS_SUFFIX**类。

GENERATED_HELPER_CLASS_SUFFIX* 为_EpoxyHelper*

className为注解所在类

生成的类为ControllerHelper子类。在生成的类里会创建被AutoModel注解的对象

ModelViewProcessor分析

先来看下Processor处理流程

各注解作用:

  1. ModelView

    1. 该注解用于自定义view.用于创建model

    2. autoLayout

      1. 当设置了这个值后,会在生成model类的时候,多生成一些设置view的属性代码,比如在buildView里增加:setLayoutParams,属性转代码对应关系如下:
  2. ModelProp

    1. 在自定义view中的settter使用该注解定义model属性
  3. TextProp

    1. view的属性,区别于ModelProp。只能用于调用参数为CharSequence 的属性
  4. CallbackProp

    1. 同样是view属性,作为一个callback.
  5. OnViewRecycled

    1. 当view被回收时,修饰的方法将会被调用
  6. OnVisibilityChanged

    1. 当view可见区域变化时,OnVisibilityChanged修饰的方法会被调用
  7. OnVisibilityStateChanged

    1. 当view可见状态的属性变化时,OnVisibilityStateChanged修饰的方法会被调用
  8. AfterPropsSet

    1. 当view的所有属性都被设置后,AfterPropsSet修饰的属性会被调用

源码分析

分析之前我们先来复习一下如何实现一个最简单的recyclerview:

  1. 实现Recyclerview的Adapter

    1. 实现public abstract VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType); 返回创建的viewholder实例

    2. 实现public abstract void onBindViewHolder(@NonNull VH holder, int position);将viewholder与数据绑定

  2. 将adapter与recyclerview绑定

  3. 设置recyclerview的的layoutmanager

我们再来看看Epoxy如何实现一个简单的列表:

  1. 用注解定义model。

  2. 创建EpoxyController的子类

  3. 在EpoxyController子类的protected abstract void buildModels(T data); 里添加model.

我们知道Epoxy内部也是基于Recyclerview来实现的。我们从EpoxyController为作入口来分析,找出从EpoxyController到Adapter.onCreateViewHolder的过程:

image

该类中有个对象:private final EpoxyControllerAdapter adapter;类结构如下:

image

其父类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发起。此方法由用户发起。