快速滚动时,getView调用错误的位置

Dro*_*mon 9 android scroll android-listview

相当新的Android开发人员.

我遇到了一个奇怪的问题,我不知道如何解决.我在这里读到了很多问题,听起来就像我遇到的问题一样,但他们问题的解决方案似乎永远不适用于这里发生的事情.

我有一个自定义listView设置使用一个单独的类扩展BaseAdapter并使用一个视图持有者(我设置这个看着自定义列表视图的各种不同的例子).它有一个文本视图,一个按钮,一个进度条和一个图像按钮,这些项目是根据用于下载文件的AsyncTask隐藏/更改的.

当我慢慢滚动列表时,一切正常.当我快速上/下滚动列表时,就好像列表中某些单元格的视图被重新分配给其他单元格一样.

我把这行放在我的适配器类中的"getView"方法的顶部:

    @Override
    public View getView(final int pos, View convertView, ViewGroup parent)
    {
        Log.i("ks3","getView called, position is " + pos);
Run Code Online (Sandbox Code Playgroud)

我的列表中有7个项目,其中6个适合屏幕.首次显示时,我会在日志中看到:

getView called, position is 0
getView called, position is 1
getView called, position is 2
getView called, position is 3
getView called, position is 4
getView called, position is 5
Run Code Online (Sandbox Code Playgroud)

当我慢慢向下滚动到下一个项目时,接下来打印出来:

getView called, position is 6
Run Code Online (Sandbox Code Playgroud)

当我向上滚动时,这个:

getView called, position is 0
Run Code Online (Sandbox Code Playgroud)

往下走,慢慢地完美地产生这些结果.

当我开始快速地来回滚动时,它会打印出这个消息很多次,大多数显示6和0作为位置,但偶尔我也会看到这些:

getView called, position is 1
getView called, position is 5
Run Code Online (Sandbox Code Playgroud)

位置1和5不应该被调用,因为它们总是在屏幕上.就好像getView一样混乱了.与此同时,正如我之前所说,我的名单看起来很奇怪.图像按钮将在不应该移动的单元格中向上或向下移动.

如果我回去顺利滚动,我再次看到只有0和6的位置.

老实说,我不确定如何解决这个问题.我想也许我可以限制你在列表中滚动的速度,但是找不到任何有效的东西.

谢谢!

编辑:我想更新一些关于这个问题的事情.第一个是,从这里的评论和listView上的谷歌视频,我注意到getView可以被调用其他东西然后我想象的那样,例如测量,所以我不应该惊慌通过我最初认为是我的问题的一部分(因为我认为getView被错误的位置调用).

其次,我多次看到"在适配器中缓存视图"是一个非常糟糕的主意.我不清楚这意味着什么,但我很确定这是我做错的事情之一(我保存了一个按钮实例,progressBar,imageButton ......).

那个,以及我更新getView以外的视图的事实,我不使用notifyDataSetChanged(); 那些在一起可能会导致一些不稳定的事情发生.

Arg*_*yle 13

你是正确的,ListView重复使用屏幕上不同位置的视图.通过不一直分配新视图来优化以保持内存使用的合理性和快速性.

您可能使用LiewView不当.观看关于如何正确使用ListView以获取整个故事的演讲,但这里是亮点:

  1. "位置"是指数据在适配器列表中的位置.如果适配器数据在数组中,那么这将是该数组的索引.
  2. "ID"是指数据本身的价值.如果你有一个名单并使用它们,他们的位置会改变,但他们的ID不会.
  3. "索引"指的是视图相对于可视屏幕区域的相对位置.你可能永远不需要这个.
  4. 不要在适配器的getView()方法之外操纵视图(或尝试缓存它们),否则会出现奇怪的行为.
  5. 如果调用getView(int, View, ViewGroup)提供视图实例,则填充其字段而不是全新视图.假设您已正确实施getItemType(),您将始终获得正确的View类型以重新填充.
  6. getView()尽可能快地使你的方法,并且只对其他线程进行繁重的提升.
  7. 仅仅因为调用的容器getView()不一定意味着将显示数据.框架将这些用于测量目的.由于工作可以被丢弃,这是确保getView()尽可能快地完成工作的另一个原因.
  8. 当您需要在屏幕上显示数据时,请说明您的下载已完成,就在您拨打电话时notifyDataSetChanged().不要直接调整视图,它们将在重新绘制时在下一个UI循环中填充.

刚刚花了几天时间改造一个ListView天真的实施,我感到很痛苦.但结果是值得的!

  • 阿盖尔,非常感谢你的链接.我不太了解listView的工作原理,我承认我正在更新getView之外的视图,因此我将不得不弄清楚如何使用notifyDataSetChanged(). (2认同)