【问题标题】:Understanding RecyclerView.ViewHolder了解 RecyclerView.ViewHolder
【发布时间】:2018-01-14 00:15:35
【问题描述】:

我很难理解视图持有者的工作,这是我的一些问题,可以增加我对视图持有者的理解:

据说oncreateViewHolder返回viewholder对象,viewholder对象是什么,它包含单行的所有视图吗?如果有 1000 个项目的列表,将创建多少个视图对象?

我的理解: 如果我们正在创建viewholder对象,它包含像findviewbyid这样的视图引用,因为findviewbyid是扩展操作,所以我们可以通过viewholder创建单个viewholder对象并通过设置图像或文本来重用(发生在onBindView中)。

但是 onCreateViewHolder 运行多次,结果 findviewbyid 也会执行多次,是不是性能问题?

还有它与简单列表视图的基本适配器的convertView有何不同

谢谢!

【问题讨论】:

    标签: java android listview android-recyclerview android-adapter


    【解决方案1】:

    RecyclerView.ViewHolder 是一个辅助类,用于保存一行或多行的视图。 为每个 viewType 创建一个或多个 ViewHolder。

    如果多行具有相同的 ViewType,则可以将同一 View 用于多行。

    覆盖getItemViewType(int position) 是拥有多种视图类型的方法。如果getItemViewType 返回一个未使用的viewType,那么onCreateViewHolder 将被调用来创建一个新的ViewHolder。

    适配器onBindViewHolder 是用每一行的特定数据填充视图的地方。

    添加:

    必须明确一个概念:使 ViewHolder 可重用的原因在于它共享相同的 viewType。 相反,如果您让getItemViewType(int position) 为每一行返回不同的值,那么每一行都会有其独立的 ViewHolder 和视图。

    【讨论】:

    • 是否重用内部视图?我们不必维护?还有它与listview的convertView有何不同以及为什么我们首先检查它是否为null
    • 对我来说,比较没有多大意义,RecyclerView 的工作方式不同,因为我使用 RecyclerView,然后 ListView getView 是如何工作的,它的 convertView 参数是一个被遗忘的主题。您不需要在 onCreateViewHolder 中检查 null。
    • 谢谢,添加recycleriew库怎么样,它的版本应该与appcompat库版本匹配吗?
    • 是的,两者的版本相同。我在答案中添加了更多文字。
    • 是的,谢谢@Tonteria24 :)
    【解决方案2】:

    据说oncreateViewHolder返回viewholder对象,是什么 viewholder 对象是否包含单行中的所有视图?如果 有 1000 个项目的列表,将创建多少个视图对象?

    一个视图行的一个 ViewHolder 对象。每次调用 onCreateViewHolder 时都会创建一个 ViewHolder 对象。它是根据设备中可见项目的数量来调用的。即使你有 100 个项目,如果只有 10 个项目可见,onCreateViewHolder 将被调用 10 次,将有 10 个 ViewHolder。 (基于 RecyclerView 优化可能会有一两个额外的项目,因为如果您滚动列表,下一个项目应该立即可见)

    我的理解:如果我们正在创建它包含的 viewholder 对象 像 findviewbyid 这样的视图参考,因为 findviewbyid 是广泛的 操作,所以通过 viewholder 我们可以创建单个 viewholder 对象和 只需设置图像或文本即可重用(发生在 onBindView 中)。

    RecyclerView 已经在回收和重用 View 和相应的 ViewHolders。任何时候出现的 ViewHolder(和 View)的数量取决于屏幕上可见项目的数量。

    但是 onCreateViewHolder 运行了多次,结果 findviewbyid 也会执行多次,是不是性能问题?

    如前所述,这将被调用的次数仅适用于可见项目的数量。滚动时,视图和视图持有者会被重用。每行都有不同的视图。所以每一行都会有不同的 ViewHolder 。

    还有它与 simple 基本适配器的 convertView 有何不同 列表视图

    在 ListView 中,convertView 是旧视图,它提供了在滚动列表时为新行重用相同视图的选项。但它是可选的,因为开发人员可能根本不使用 convertView。在 RecyclerView 中,旧视图的重用是自动完成的。

    【讨论】:

    • 是否重用内部视图?我们不必维护?还有它与listview的convertView有何不同以及为什么我们首先检查它是否为null
    • 是的,重用旧视图是自动完成的。我已经更新了关于 convertview 的答案。
    • 添加recycleriew库怎么样,版本应该和appcompat库匹配吗?
    • 是的。建议所有支持库使用相同的版本 - RecyclerView、appcompat v7、design、CardView...
    • 谢谢@Bob :)
    【解决方案3】:

    视图持有者它可以帮助您减少通过 id 调用查找视图。 举个例子吧。

    假设您有 1k 个项目,每个项目都有 5 个视图,您需要通过 id 查找,并且屏幕上只能显示 5 个完整项目。

    因此,recyclerView 将创建 7 个(5 + 一个未满底部和一个未满顶部)视图持有者。下次滚动 recyclerView 时,它将使用 existing viewHolders。正如名字所说:“RecyclerView”

    所以 findViewById 将被调用 7*5=35 次。 如果您不使用 viewHolder,您将获得 5*1000 = 5000 次调用。

    35 对 5000,所以你理解我的想法。

    【讨论】:

    • 是否重用内部视图?我们不必维护?还有它与listview的convertView有何不同以及为什么我们首先检查它是否为null
    • @blackHawk 是的,RecyclerView.Adapter 为您完成。但是,如果您想知道它是否有效,请阅读此内容(在 list viewHolder 示例中,因为 list View 没有默认使用视图模式的适配器):dzone.com/articles/optimizing-your-listview
    • 谢谢:),添加recycleriew库怎么样,它的版本应该与appcompat库版本匹配吗?
    • @blackHawk 不,它不应该,但请记住,您应该保持它是最新的,通常,最新的意思是“与最新的 app-compat 版本相同”,但是并非总是如此。
    • 谢谢@Valia :)
    【解决方案4】:

    假设您要显示 1000 个项目的列表,而屏幕上只有 10 个项目对用户可见。您的适配器会创建 10 个 ViewHolder 实例来同时显示它们。当用户滚动并且适配器必须显示更多项目时,它不会创建 ViewHolder 的新实例,而是重用不再可见的项目。您的适配器会阻止创建新视图并通过这样做来节省 CPU 时间。

    【讨论】:

    • 是否重用内部视图?我们不必维护?还有它与listview的convertView有何不同以及为什么我们首先检查它是否为null
    • 你说的是对的,但还不够。它不仅会创建 10 个查看器。它将创建更多以实现平滑滚动。因此,当用户滚动列表时,您将拥有 10 个视图和更多视图以显示它们。
    • @blackHawk AFAIK,重用是您的适配器内部的,您无需做任何事情。在 convertView 中,您应该手动设置标签,以便以后可以重用它。
    • 感谢@Leanadro 纠正我。我不确定确切的金额。
    • 好的,你说会有10个viewholder加上几个viewholder?如果是旧的 listview,listview 会创建多少个 viewholder?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多