【问题标题】:Android. How does notifyDataSetChanged() method and ListViews work?安卓。 notifyDataSetChanged() 方法和 ListViews 是如何工作的?
【发布时间】:2012-08-27 03:01:15
【问题描述】:

我正在尝试理解ListView 的概念及其工作原理,并且我正在尝试创建自己的适配器来扩展BaseAdapter。例如,对于ArrayAdapter,有一个notifyDataSetChanged() 方法应该在您更新包含所有数据的数组列表后调用,以刷新ListView

但我正在创建自己的 BaseAdapter 子类。我无法使用该方法,或者是吗?我如何实现这个方法?基本上,那个方法到底是做什么的,也许我会明白。

如果是ArrayAdapter,我猜它会查看ListView 当前显示的位置,并在更新后检查它是否与ArrayList 中的位置相同?或者……

上面写着方法:

通知附加的观察者基础数据已被 发生变化,任何反映数据集的视图都应自行刷新。

但它究竟是如何刷新自己的呢?

谁能解释一下?

【问题讨论】:

    标签: android android-listview android-adapterview


    【解决方案1】:

    我想通了。我无法理解适配器到底是如何启动的,以及它是如何知道从哪里获取数据的。当我扩展BaseAdapter 类时,在该类的构造函数中,我初始化了我想在ListView 中看到的项目列表。但我无法弄清楚这些值将如何使用以及何时使用。

    事情就是这样!!! :

    BaseAdapter 中有一些方法需要被覆盖。其中有getCount()

    ListView 被创建时,它会调用getCount()。如果这返回一个不同于 0 的值(我返回了我之前在构造函数中初始化的 ArrayList 的大小),那么它会调用 getView() 足够的时间来用项目填充屏幕。 例如,我用 20 个项目初始化了 ArrayList。因为最初只有 8 个项目适合屏幕,getView() 被调用了 8 次,每次都要求我返回所需的位置(更准确地说,它想知道该行在该特定位置的列表中的样子,它需要包含什么数据)。如果我向下滚动列表,getView() 会被一遍又一遍地调用,直到我到达列表的末尾,在我的例子中是 20 个项目/行。

    notifyDataSetChanged() 所做的是......当被调用时,它会查看调用时屏幕上显示的项目(更准确地说是哪些行索引)并使用这些位置调用getView()

    ie 如果您正在显示列表中的前 8 个项目(因此这些是屏幕上可见的项目)并且您在列表中的第 2 和第 3 项之间添加了另一个项目并且您调用notifyDataSetChanged() 然后调用getView() 8 次,位置从0 开始,以7 结束,并且因为在getView() 方法中,您从ArrayList 获取数据,然后它将自动返回插入的新项目在前 8 个中的 7 个旁边的列表中(7 个而不是 8 个,因为最后一个项目下降了一个位置,所以它不再可见),ListView 将用这些项目重绘,或者其他什么。

    另外,需要说明的是,如果您正确实施了getView(),您最终将回收已显示的项目(对象)(而不是创建新项目)。请在 12:00 左右查看 this video,了解实现 getView()

    的正确方法

    我已经通过在每个方法中调用LogCat 并关注发生的事情来解决所有这些问题。

    希望这对刚刚开始了解ListViews 工作原理的人有所帮助。

    附: This example对我理解也有很大帮助。

    更新

    现在ListViews 已经不再使用了。 Android 推出了RecyclerView,它为您回收视图,但了解ListView 的基础知识有助于理解RecyclerView

    这里有一个链接供参考:https://developer.android.com/guide/topics/ui/layout/recyclerview

    【讨论】:

    • 嗯,这是一个很好的解释。但我们认为您知道 ListView 的工作原理。
    • 因为最初只有 8 个项目适合屏幕,所以 getView() 被调用了 8 次。这并不总是正确的,因为适配器可以调用一些额外的getViews 进行测量。
    • 如何将适配器链接到 ListView?我有一个非常相似的问题,在过去的 3 个小时里我一直坚持! stackoverflow.com/questions/35098789/listview-arraylist/…
    【解决方案2】:

    BaseAdapter 可以被其他类“观察”。当您调用 ListView setAdapter() 的方法时,它会调用适配器的 registerDataSetObserver。因此,适配器知道谁对新数据感兴趣。

    您可以查看BaseAdapterhere的来源。它很小。

    notifyDataSetChanged 可供您使用,您基本上不应该覆盖它(因为它没有做任何特别的事情,所以您可以在自己的类中重用它)。

    【讨论】:

    • 如何将我的适配器链接到我的数组列表?
    【解决方案3】:

    假设您的ListView 显示存储在ArrayList 中的一些数据。

    更改ArrayList的内容后,需要告诉列表数据源发生了变化,需要重新绘制自身以显示新数据。

    所以,这就是 notifyDatasetChanged() 出现的地方。它告诉ListView 数据已被修改;为了显示新数据,ListView 必须重新绘制。

    【讨论】:

    • 嗯,这就是我没有得到的。我在哪里告诉适配器我正在使用某个 ArrayList 来存储数据?当我使用 ArrayAdapter 时,是的,当我将适配器链接到 ListView 时,我会发送对 ArrayList 的引用,但是当我扩展 BaseAdapter 时呢?它怎么知道从我的 ArrayList 中获取值?
    • 那么,当notifyDatasetChanged() 被调用时,我会强制ListView 为屏幕中显示的当前项目调用getView() 方法?
    • 哦。因此,当调用 notifyDatasetChanged() 时,它不会为 ListView 中显示的当前位置调用 getView(),因此会刷新显示的当前项目,以防我们修改了这些项目?
    • 呃,你指的是我吗?我不认为我在这篇文章中制作过任何以前的 cmets 并删除了它们。无论如何,尝试从网上获取有关自定义 listView 的教程,看看他们在那里遵循的步骤?
    • 当您调用 notifyDatasetChanged() 时,它会再次重绘整个列表,而不仅仅是任何特定的视图。实际上,invalidate() 也做了类似的事情。
    【解决方案4】:

    当您为自己扩展 BaseAdapter 以创建子类时,您也将获得 notifyDataSetChanged() 方法。

    【讨论】:

      猜你喜欢
      • 2013-04-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-09
      • 2021-12-30
      • 1970-01-01
      • 1970-01-01
      • 2018-01-29
      相关资源
      最近更新 更多