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

2023-09-13 00:29:00 作者:我说Fuck怎么了

在这里相当新的Andr​​oid开发者。

fairly new Android developer here.

我遇到一个奇怪的问题,我不知道如何解决。我读了很多在这里的问题,听起来像它们是同一个问题,我有,但是解决他们的问题似乎从来没有适​​用于这里究竟是怎么回事。

I've come across a strange problem that I'm not sure how to work around. I've read a lot of problems around here that sound like they are the same problem I am having, but the solutions to their problems never seemed applicable to what is going on here.

我有一个自定义的ListView设置使用扩展BaseAdapter和使用视图持有人(我设置此寻找列表视图定制各种不同的例子)一个单独的类。它有一个文本视图,一个按钮,一个进度条,以及图像按钮,这些项目被隐藏/改基础上的AsyncTask来下载文件。

I have a custom listView set up using a separate class that extends BaseAdapter and uses a view holder (I set this up looking at various different examples of custom listviews). It's got a text view, a button, a progress bar, and an image button, and these items are hidden/changed based on an AsyncTask used to download a file.

一切正常,当我在列表中滚动缓慢。当我滚动列表迅速上升/下降,这是因为如果某些细胞的列表中的次得到重新分配给其他细胞。

Everything works fine when I scroll through the list slowly. When I scroll the list rapidly up/down, it is as if the views of some cells in the list get re-assigned to other cells.

我把此行到我的getView法顶在我的适配器类:

I put this line into the top of my "getView" method in my adapter class:

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

我在我的名单7个项目,其中6适合在​​屏幕上。当它第一次被显示出来,我看到在我的日志:

I have 7 items in my list, and 6 of them fit on screen. When it first gets displayed, I see this in my log:

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

当我向下滚动慢慢到下一个项目,这是打印出下一个:

When I scroll down slowly to the next item, this is printed out next:

getView called, position is 6

当我向后滚动起来,这样的:

When I scroll back up, this:

getView called, position is 0

去向下和向上慢慢完美无缺产生这些结果。

Going down and up slowly produce these results flawlessly.

当我开始来回滚动很快,它打印出此消息一帮次,多出6和0的位置,但有时我会看到这些孩子的:

When I start scrolling back and forth quickly, it prints out this message a bunch of times, mostly showing 6 and 0 as the position, but occasionally I will see these as well:

getView called, position is 1
getView called, position is 5

的位置1和5不应该获取调用,因为它们总是在屏幕上。这是因为如果getView得到了所有混乱的。同时,正如我前面所说,我的名单看起来怪怪的。图像按钮会向上或向下移动一个单元格,他们不应该。

Positions 1 and 5 should not be getting called, as they are always on-screen. It is as if getView got all jumbled up. At the same time, as I stated before, my list will look strange. Image buttons will be moved up or down a cell where they should not be.

如果我回去滚动顺畅,我看到的只有0和6的卡位了。

If I go back to scrolling smoothly, I see only 0's and 6's for position again.

老实说,我不知道如何来解决这一点。我想也许我可以限制你的速度有多快能够在列表中滚动,但一直没能找到任何工作。

I honestly am not sure how to work around this. I thought maybe I could limit how fast you are able to scroll through the list, but haven't been able to find anything that works.

谢谢!

编辑: 我想更新关于这个问题,有两件事情。 ,从评论这里,并从谷歌视频的ListView,它已经到了我的注意,getView可以要求其他的东西,然后我想象它是为,如测量值,所以我不应该感到恐慌第一个是由我本来还以为是我的问题的一部分(也就是说,我认为getView正在调用了错误的位置)。

I wanted to update a couple things regarding this question. The first being that, from a comment here and from the Google video on listView, it has come to my attention that getView can be called for other things then what I imagined it was for, such as measurements, and so I should not be alarmed by what I originally thought was part of my problem (that being that I thought getView was being called with the wrong positions).

其次,我看了多次,这是一个非常糟糕的主意,你的缓存适配器内部的意见。我不是这句话的意思是很清楚,但我pretty的肯定这是对的事情我做错了一(我保存了按钮的一个实例,进度,ImageButton的...)。

Secondly, I saw multiple times that it is a very bad idea to "cache views inside your adapter." I am not exactly clear on what this means, but I'm pretty sure it is one of the things I am doing wrong (I save an instance of a button, progressBar, imageButton...).

这,连同我更新视图getView之外,我不使用notifyDataSetChanged()的事实;那些在一起很可能导致一些靠不住的东西发生。

That, along with the fact that I update the views outside of getView and I don't use notifyDataSetChanged(); those together are probably causing some wonky stuff to happen.

推荐答案

您是正确的,的ListView 被重复使用的意见在屏幕上不同的地方。这是一个优化,以保持内存使用合理,快速的通过不分配新的看法所有的时间。

You are correct that ListView is reusing views in different places on the screen. It's an optimization to keep memory use reasonable and speedy by not allocating new views all the time.

有机会,你正在使用 LiewView 不正确。关注这次谈话对如何正确使用的ListView 获得整个故事,但这里的亮点:

Chances are that you're using LiewView incorrectly. Watch this talk on how to properly use ListView to get the whole story, but here's the highlights:

在位置指的是你的数据在适配器列表中的位置。如果适配器的数据是在一个数组,这将是索引到该阵列。 标识是指数据本身的值。如果你有名字的名单,并诉诸它们,它们的位置会发生变化,但它们的ID不会。 指数指的是一个视图的相对位置相对于所述可视屏幕区域。你可能永远不会需要这个。 请不要操作意见(或试图对其进行缓存),您的适配器 getView()方法之外,否则你会得到奇怪的行为。 如果调用 getView(廉政,查看,ViewGroup中)提供了一个视图实例,填充,而不是夸大全新的意见的领域。假设你已经正确实施 getItemType(),您总能获得正确的查看键入重新填充。 请您 getView()方法一样快,你可能可以,并且只能做繁重的其他线程。 正因为容器名为 getView()并不一定意味着该数据将显示。该框架使用这些测量的目的。由于工作可以扔掉,这是另一个原因,以确保 getView()是一样快,你可以​​做到这一点。 当事情发生在你的数据,你需要在屏幕上显示,说你下载完成后,当你调用的 notifyDataSetChanged()。其观点直接不甘示弱,他们将在接下来的UI循环进行填充时,它被重新绘制。 "Position" refers to the location of your data in the adapter list. If your adapter data is in an array, this would be the index into that array. "ID" refers to the value of the data itself. If you have a list of names and resort them, their position will change, but their ID will not. "Index" refers to the relative location of a view with respect to the viewable screen area. You'll probably never need this. Do not manipulate views (or attempt to cache them) outside of your adapter's getView() method or you will get strange behavior. If the call to getView(int, View, ViewGroup) provides a view instance, populate its fields instead of inflating totally new views. Assuming you've correctly implemented getItemType(), you'll always get the right View type to repopulate. Make your getView() method as fast as you possibly can, and only do heavy lifting on other threads. Just because the container called getView() doesn't necessarily mean the data will be displayed. The framework uses these for measurement purposes. Since the work could be thrown away, this is another reason to make sure that getView() is as fast as you can make it. When something happens to your data which you need to show on screen, say your download is complete, that's when you call notifyDataSetChanged(). Don't fiddle with the views directly, they'll be populated on the next UI loop when it gets redrawn.

说完刚花了几天再加工的ListView 这是天真地实施,我觉得你的痛苦。该结果是值得的,但!

Having just spent a few days reworking a ListView that was implemented naively, I feel your pain. The results have been worth it, though!