安卓 - StableIDs 是什么意思?

51

我正在实现ExpandableListView的ListAdapter,工作时发现需要重写函数boolean hasStableIds()。 请问有人能解释一下稳定id的含义吗?什么情况下需要使用它?

2个回答

67

稳定的ID允许ListViewnotifyDataSetChanged调用之间项目保持不变的情况下进行优化。它所指的ID是从getItemId返回的那些ID。

如果没有稳定的ID,ListView就必须重新创建所有的View,因为它无法知道数据变更时是否保留了项目ID(例如,如果ID只是数据中的索引,则必须重新创建所有内容)。有了它,它可以避免重新创建保持其项目ID的Views。


4
“如果ID只是数据中的索引,那么它必须重新创建所有内容” 这句话应该不符合事实吧?我的意思是,如果ID只是索引,那么它始终是稳定的,因为它永远不会改变。索引n处的元素将始终返回n作为ID,因此永远不会被更改。我的逻辑得到了@DanyloVolokh所提供解释的支持。 - Nouvel Travay
2
如果你使用getItemId返回的数组索引,并且需要hasStableIds,请注意这一点。我承认,措辞不是很好。欢迎编辑 :) - Delyan
1
只是为了明确,根据文档此处,当一个id保证引用一个特定的唯一对象时,它应该返回true,这意味着id的变化表示对象已经改变,而id保持不变则意味着它不是某个新对象返回相同的id,在这种情况下,视图必须更新并且需要返回false - Karuhanga
没有它,ListView 就必须重新创建所有的视图。相反,视图在 RecycledViewPool 中并应该被回收利用。对我来说,稳定的 ID 的优点是你不需要再次绑定它们。或者我错过了什么吗? - mbonnin

21
如果hasStableIds()返回false,则每次调用notifyDataSetChanged()时,您的适配器将查看getItemId的返回值,并最终调用getView(int position,View convertView,ViewGroup parent)。如果hasStableIds()返回true,则只有当它们的ID发生更改时才会执行此操作。

使用此技术,您可以轻松更新ListView中的单个项目

如果您正确实现了getItemId,那么它可能非常有用。

例如:

您有一个专辑列表:

class Album{
     String coverUrl;
     String title;
}

你可以像这样实现getItemId

@Override
public long getItemId(int position){
    Album album = mListOfAlbums.get(position);
    return (album.coverUrl + album.title).hashCode();
}

现在您的项目ID取决于coverUrltitle字段的值,如果您更改它们并在适配器上调用notifyDataSetChanged(),则适配器将调用每个元素的getItemId()方法,并且仅更新ID已更改的那些项目。

如果您在getView()中执行一些“繁重”的操作,则此功能非常有用。


3
我认为你的意思是“If hasStableIds() 返回 true”,对吗? - Stan Mots
2
不,我的意思是“false”。当ID不稳定时。(可变的) - Danylo Volokh
20
这个答案完全错误。RecyclerView只有在项目具有稳定的ID且调用setHasStableIds(true)时才能以这种方式避免不必要的工作。在任何情况下,示例代码都不会按照作者所说的那样工作。hasStableIds()询问有关项目“标识”的问题,而不是关于项目“值”的问题。如果hasStableIds()返回false,则适配器必须在每次更新时重新创建所有视图,因为它不能假设具有相同ID的列表项对应于相同的数据。 - Clement Cherlin
2
除了@ClementCherlin的评论之外,hashCode方法不可靠作为标识符使用。请记住,哈希值不能保证唯一性,而是无法避免冲突。在哈希函数中,冲突非常普遍,对于大型数据集,它们可能会导致提供的数据和显示的数据之间的不一致性。 - koperko
1
它看起来像是 DiffUtils 的简化版本。 - Shubham AgaRwal
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接