广告位联系
返回顶部
分享到

Epoxy - 在RecyclerView中构建复杂界面

Android 来源:稀土掘金 作者: bytebeats 发布时间:2022-09-17 18:54:31 人浏览
摘要

Diffing 对于复杂数据结构支持的多个视图类型展示在屏幕上, Epoxy此时是尤其有用的. 在这些场景中, 数据可能会被网络请求, 异步 Observable, 用户输入, 或者别的来源更新, 这些源会请求更

Diffing

对于复杂数据结构支持的多个视图类型展示在屏幕上, Epoxy此时是尤其有用的. 在这些场景中, 数据可能会被网络请求, 异步 Observable, 用户输入, 或者别的来源更新, 这些源会请求更新 Model 并且通知适配器恰当变更.

手动追踪这些变更很困难, 且直接增加了显著的开销. 在这些场景下, 你可以充分利用Epoxy的自动 diffing 机制来减少开销, 同时也高效地更新变更的视图.

EpoxyController类自动使用 diffing 机制, 并且在EpoxyAdapter类中可以作为选项开启.

追踪 Model 状态

Epoxy在每个 Model 上调用equals和hashCode来判断 Model 的当前状态以及 Model 何时发生了变更. 对于每个 Model 而言, 正确地实现这些方法对于 diffing 正常工作很重要.

Epoxy生成 Model 子类来避免手动实现equals和hashCode的开销.

异步支持

EpoxyController支持在后台线程执行 diff 算法来提高性能. 查看这里获取更多细节.

最佳实践

在使用 diffing 时, 有一些性能隐患需要明白.

首先, diffing 必须处理列表中的全部 Model, 有成百上千个 Model 的话, 可能会影响 Controller 的性能. 大多数情况下 diffing 算法线性时间执行, 但依然必须处理列表中的全部 Model. 无论如何, 项的移动很慢, 在最坏情况下, 比如洗牌列表中的全部 Model, 性能是 (n^2)/2.

其次, 每一次 diff 必须通过equals/hashCode计算 Model 的状态, 来决定项变更. 在这些实现中避免导入不必要的计算会显著地拖慢 diff.

还有, 要清楚无意间修改 Model 状态, 例如点击监听器. 举个例子, 在 Model 设置点击监听器是很普遍的做法, 监听器会在 View 绑定的时候设置. 容易犯的错误是使用匿名内部类作为点击监听器, 这会影响 Model 状态, 并且在 Model 更新或者重建的时候请求视图重新绑定. 在这个场景下可以使用DoNotHash选项(@EpoxyAttribute(DoNotHash)告知生成的 Model 将该字段从状态的计算中排除出来). 另一个常见错误是在 Model 绑定调用期间修改 Model 状态.

注意该算法 - Android支持库类DiffUtil用于在EpoxyController中执行diffing. 由于历史原因, 更早的EpoxyAdapter使用了自定义方案进行diffing.

配置

有几个配置选项用来控制Epoxy的注解处理器的行为.

可用选项

  1. 要求抽象 Model - 如果启用了该选项, 那么任何包含Epoxy注解的Epoxy Model类必须是抽象的, 否则编译期将抛出错误. 拥有抽象模型有助于防止意外使用基本模型类而不是生成的类. 该选项默认设置为false.
  2. 要求Epoxy Model 的属性字段实现 equals和hashCode - 如果该选项启用的话, 那么注解处理器将会检查每一个注解了@EpoxyAttribute的字段, 并且确保该类型的字段实现了equals和hashCode. 如果没有实现的话, 编译期错误将会抛出. 为了 Model 状态能够正确决定diffing正常工作, 属性类型实现equals和hashCode很有必要. 启用该选项在意外使用了未实现equals/hashCode的类型时能够帮助捕获异常. 该选项默认是禁用的.
  3. 验证生成的Epoxy Model的使用 - 如果该选项启用的话, 生成的Epoxy Model会添加验证以确保该Model在EpoxyController中正确地使用. 包括: 确保 Model 没有在 Controller 中添加多次, Model 在添加之后没有被修改, 以及风格一致性保证(如果使用了Paris的话). 如果这些条件被违反的话, 将会抛出运行时异常. 这将强制将 Model 当作不可变对象对待, 一旦它被添加进Controller, 这将极大地鼓励EpoxyController的恰当使用, 并且防止 Model 在 diff 之后, 意外的 View 状态发生. 该选项默认是开启的, 但你也许喜欢在生产环境禁用掉它, 防止运行时验证的开销, 毕竟运行时验证开销挺大的.
  4. 隐式添加AutoModels - 如果启用该选项的话, 那么该注解创建的 Model 在被修改之后将自动地添加到 Controller. 点击文档查看详情. 该选项默认是禁用的.
  5. 禁止生成Kotlin扩展函数 - 默认情况下, 在使用 kapt 时, Model扩展函数 会自动生成. 可以通过设置disableEpoxyKotlinExtensionGeneration为false全局禁用.

控制这些选项

In gradle

所有的这些选项在build.gradle文件中能够设置为注解处理器选项.

project.android.buildTypes.all { buildType ->
  buildType.javaCompileOptions.annotationProcessorOptions.arguments =
      [
          // Validation is disabled in production to remove the runtime overhead
          validateEpoxyModelUsage     : String.valueOf(buildType.name == 'debug'),
          requireHashCodeInEpoxyModels: "true",
          requireAbstractEpoxyModels  : "true",
          implicitlyAddAutoModels     : "true"  
      ]
}
复制代码

对于拥有许多 Model 和贡献者的大型项目, 使用这些选项尤其有用. 在这些场景下, Model拥有标准模型极大地缩减了创建和使用 Model 时的错误.

In Java

候选情况下, 可使用@PackageEpoxyConfig包注解为每一个包下的 Model 指定配置选项. 在该包下创建package-info.java. 不过这种方式不能修改validateEpoxyModelUsage选项.

@PackageEpoxyConfig(
    requireAbstractModels = true,
    requireHashCode = true,
    implicitlyAddAutoModels = true
)
package com.example.app;

import com.airbnb.epoxy.PackageEpoxyConfig;
复制代码

如果包下没有找到配置选项, 那么来自最近父包下的配置将被使用. 如果全部父包都没有声明配置, 那么设置在build.gradle文件里面的注解处理器将被使用. 如果build.gradle文件中也没有配置, 那么将使用默认值


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 : https://juejin.cn/post/7144173582698938381
相关文章
  • Kotlin的Collection与Sequence操作异同点介绍

    Kotlin的Collection与Sequence操作异同点介绍
    在Android开发中,集合是我们必备的容器,Kotlin的标准库中提供了很多处理集合的方法,而且还提供了两种基于容器的工作方式:Collection 和
  • 实现一个Kotlin函数类型方法

    实现一个Kotlin函数类型方法
    接口与函数类型 业务开发中,经常会有实现一个函数式接口(即接口只有一个方法需要实现)的场景,大家应该都会不假思索的写出如下代
  • Android10 App启动Activity源码分析
    ActivityThread的main方法 让我们把目光聚焦到ActivityThread的main方法上。 ActivityThread的源码路径为/frameworks/base/core/java/android/app/ActivityThread。 1 2
  • Android10客户端事务管理ClientLifecycleManager源码解析

    Android10客户端事务管理ClientLifecycleManager源码解析
    在Android 10 App启动分析之Activity启动篇(二)一文中,简单地介绍了Activity的生命周期管理器是如何调度Activity进入onCreate生命周期的流程。这
  • Kotlin对象的懒加载方式by lazy与lateinit异同介绍

    Kotlin对象的懒加载方式by lazy与lateinit异同介绍
    属性或对象的延时加载是我们相当常用的,一般我们都是使用 lateinit 和 by lazy 来实现。 他们两者都是延时初始化,那么在使用时那么他们两
  • Android类加载流程分析

    Android类加载流程分析
    本文分析的代码基于Android8.1.0源码。 流程分析 从loadClass开始,我们来看下Android中类加载的流程 /libcore/ojluni/src/main/java/java/lang/ClassLoader.ja
  • Android实现读写USB串口数据的代码

    Android实现读写USB串口数据的代码
    最近在研究USB方面的内容;先后做了关于Android读写HID、串口设备的DEMO。本文比较简单,主要介绍的是Android实现读取串口数据的功能 废话不
  • Epoxy - 在RecyclerView中构建复杂界面
    Diffing 对于复杂数据结构支持的多个视图类型展示在屏幕上, Epoxy此时是尤其有用的. 在这些场景中, 数据可能会被网络请求, 异步 Observable, 用
  • Android性能优化的详细介绍

    Android性能优化的详细介绍
    性能优化是一个app很重要的一部分,一个性能优良的app从被下载到启动到使用都能给用户到来很好的体验。自然我们做性能优化也是从被下
  • Android进阶宝典-插件化2(Hook启动插件中四大组件

    Android进阶宝典-插件化2(Hook启动插件中四大组件
    在上一节,我们主要介绍了如果通过反射来加载插件中的类,调用类中的方法;既然插件是一个apk,其实最重要的是启动插件中的Activity、
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计