首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ListActivity在onClick中注册了正确的位置,但对其ListAdapter的getView()的调用总是从0开始计数

ListActivity在onClick中注册了正确的位置,但对其ListAdapter的getView()的调用总是从0开始计数
EN

Stack Overflow用户
提问于 2010-08-31 12:38:33
回答 2查看 1.6K关注 0票数 1

我有一个ListActivity,它的ArrayAdapter-subclass创建了一个(droid-fu) WebImageView。问题是,当列表变得比在单个页面上显示的更长时,无论调用getView()的是什么,它总是从0开始并计数到4或5(取决于部分行是否可见),即使它实际上在屏幕顶部显示了像#12或14这样的项目...但是onClick()可以正确注册。

换句话说,假设列表中有27行,我让应用程序中到处都是Log.d语句来记录它所做的一切。当ListActivity开始时,我可以看到它使用position = 0、1、2、3、4和5调用getView。如果我触摸其中一行,onClick()也会以正确的位置0..4 (5在屏幕外)触发。到现在为止还好。

现在,将列表向上滑动几行,并观察日志输出。对于position=0、1、2、3、4和5,再一次调用getView()。但是如果我碰到其中一行,onClick()就会在9或14这样的位置触发(实际上,这是正确的)。

换句话说,在此过程中的某个地方,任何负责调用ListAdapter的getView()方法来呈现列表的东西都忘记了它的当前偏移量,并且总是从0开始计数,而不是从屏幕顶部的任何行开始计数。

有没有人知道从哪里开始寻找这里可能出现的问题?也许是关于这些对getView()的调用来自哪里的线索,以及用于该调用的位置arg的值是如何确定的?天哪,有没有可能在getView()的开头放一个断点,然后用Eclipse后退一步,看看对ArrayAdapter的getView()方法的调用是从哪里来的?

更新:忘记了github &现在设法获得了我的程序的副本:

代码语言:javascript
复制
private class ChatInfoAdapter extends ArrayAdapter<ChatInfo> {
    private ArrayList<ChatInfo> items;

    public ChatInfoAdapter(Context context, int resourceID, ArrayList<ChatInfo> items) {
        super(context, resourceID, items);

        this.items = items; 
        // ^^^hmmm... could THIS be the problem somehow?
    }   

    public View getView(int position, View convertView, ViewGroup parent) {
        Log.d("getView", "postion=" + position);
        View v = convertView;
        if (v==null) {
            LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = vi.inflate(R.layout.row, null);
        }

        ChatInfo info = items.get(position); 
        // ^^^ grabbing from local "items", not superclass' ArrayList. Hmmm...
        if (info != null) {
            TextView x = (TextView) v.findViewById(R.id.x);
            TextView y = (TextView) v.findViewById(R.id.y);
            //...
            String url = info.getUrl();
            //...
            WebImageView wiv = new WebImageView(getBaseContext(), iconUrl, true, arg, arg2);
            // ^^^ my slightly-hacked droid-fu WebImageView that takes some extra args
            // Even if I completely screwed it up, this class should have no effect on
            // the value of "position" when getView gets called at runtime, right?
            // Or is there a method of ImageView that might be getting mangled somewhere
            // along the line that SHOULD be reporting its position, but instead might
            // be returning 0 (which might explain why position always starts from 0).
            LinearLayout placeholder = (LinearLayout) v.findViewById(R.id.placeholder);
            placeholder.addView(wiv);
            v.setTag(info);
        }
    }

    protected void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);
        Log.d("onListItemClick", "position=" + position);
        //...
    }
}

所以..。返回到包含~20+项目的示例列表...当它第一次出现时,我在日志中看到一系列活动,如下所示:

getView: position=0 getView: position=1 getView: position=2 getView: position=3 getView: position=4 getView: position=5 (可能顺序不同,或重复多次)

此时,如果我单击最后一行,我将在日志中看到一条消息,如: onListItemClick: position=4

到现在为止还好。但如果我稍微滚动一下列表,屏幕顶部会显示向下的~2/3项,然后单击屏幕底部的行,我会在日志中看到如下所示的一系列活动:

getView: position=0 getView: position=1 getView: position=2 getView: position=3 getView: position=4 getView: position=5 (可能以不同的顺序,或重复几次) ...onListItemClick: position=20

换句话说,它知道我单击第20行,但是调用getView所显示的位置永远不会高于position=6或position=7,而且它们总是从position=0开始。

(在下面添加了其他评论,并制作了说明问题的视频)

EN

回答 2

Stack Overflow用户

发布于 2010-08-31 14:41:02

您如何确切地检查getView()使用了哪些位置?如果getView()没有接收到正确的位置,ListView将根本无法工作。根据您所说的,您的列表显示了正确的项,因此适配器一定在getView()中接收到了正确的位置。你是在说getChildAt()/getChildCount()吗?

票数 0
EN

Stack Overflow用户

发布于 2011-03-06 20:27:59

首先,我不知道WebImageView是如何工作的,但它似乎有一个回调,在它的实现中,一个方法必须更新一个视图。

使用持有者有点危险,因为如果你将一个持有者绑定到一个方法上(例如,将它设置为final),然后滚动列表,很可能这个持有者正在被另一项重用。在回调中,您正在使用一个持有者,但因为它正被另一个项重用,所以您将更新该项,因此是一个错误的视图。

我建议每个人遵循这一条非常基本的规则:

1.切勿使用由getView()方法检索到的holder对象。当您必须更新视图时,请使用此方法:

代码语言:javascript
复制
private ViewHolder getHolder (int position){
    //position is the "real" position in the list
    int first = listView.getFirstVisiblePosition ();
    int last = listView.getLastVisiblePosition ();

    if (position >= first && position <= last){
        //The item is visible, so you have to update the view with the changes that you consider
        return (ViewHolder)listView.getChildAt (position - first).getTag ();
    }else{
        //The item is not visible, so you don't have to update any view. If you want you can update the linked item returned by getItem()
        return null;
    }
}

用法:

代码语言:javascript
复制
aMethod (new aListener (){
    @Override
    public void onCallback (int position){
        //Update item if you want
        Item item = getItem (position);
            ...

        //Obtain the holder
        ViewHolder holder = getHolder (position);

        //If it's null you don't have to update anything because the item is not visible
        if (holder != null){
            //Update view
            ...
        }
    });

正如您所看到的,回调将位置作为参数返回,但不是必需的,它可以是最终的,并通过方法或类似方法作为参数传递。我已经研究和测试了大约2天(平均16小时)支架是如何工作的,这个方法解决了我所有的问题。

注意:如果您在getView()中,并且想要立即进行更新,则可以直接使用持有符。在回调中,您必须始终使用我的getHolder()方法。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3606068

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档