Android 列表视图视图持有者。何时使用,何时不使用

发布于 2024-09-08 21:50:52 字数 239 浏览 5 评论 0原文

我有一个带有自定义列表适配器的 ListView。在 getView() 方法中,我使用 ViewHolder“模式”,如 ListView14.java 的 API 演示中所示。当我第一次渲染列表时,它似乎加载正确。然而,我遇到的问题是,当我滚动列表时,我看到列表的数据显示在错误的行中(例如,应该位于第 10 行的 TextView 却显示在第 2 行中) )。但是,当我不使用视图持有者,而是每次调用 findViewById() 时,列表视图都会正确呈现。

I have a ListView with a custom list adapter. In the getView() method, am using the ViewHolder 'pattern' as shown in the API Demos for ListView14.java. When i first render the list it seems to load correctly. However, the issue i'm running into is that when i scroll the list, i'm seeing the data for the list show up in the wrong rows (i.e. a TextView that should be in row 10 is showing up in row 2 for example). However, when I do not use the viewholder, and instead call findViewById() every time, then the list view renders correctly.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

江南月 2024-09-15 21:50:52

但是,我遇到的问题是
当我滚动列表时,我
看到列表的数据显示出来
在错误的行中(即 TextView
应该在第 10 行的内容出现了
例如,在第 2 行)。

最有可能的是,您不正确地回收了行,因此您正在操作的 ViewHolders 不是您要返回的行的正确值。

这是我的一本书中的免费摘录,其中详细介绍了行回收 - 也许它将帮助您确定哪里出了问题。

However, the issue i'm running into is
that when i scroll the list, i'm
seeing the data for the list show up
in the wrong rows (i.e. a TextView
that should be in row 10 is showing up
in row 2 for example).

Most likely, you are improperly recycling your rows, such that the ViewHolders you are manipulating are not the right ones for the row you are returning.

Here is a free excerpt from one of my books that goes into more about row recycling -- perhaps it will help you identify where things are going wrong.

落花浅忆 2024-09-15 21:50:52
  • 我遇到了同样的问题,
  • 使用以下技术解决了
  • 原因:适配器未频繁加载。
  • 在您的自定义适配器类中使用访问说明符添加 ViewHolder

    私有静态类ViewHolder {
    
            受保护的 TextView 项目名称;
    
        }
    

获取视图方法

    @Override

        public View getView(int position, View view, ViewGroup viewGroup) {

            // create a ViewHolder reference
            ViewHolder holder;

            //check to see if the reused view is null or not, if is not null then reuse it
            if (view == null) {
                holder = new ViewHolder();

                view = mLayoutInflater.inflate(R.layout.list_item, null);
                holder.itemName = (TextView) view.findViewById(R.id.list_item_text_view);

                // the setTag is used to store the data within this view
                view.setTag(holder);
            } else {
                // the getTag returns the viewHolder object set as a tag to the view
                holder = (ViewHolder)view.getTag();
            }
    // now Use Holder object toget Idss 

    holder.itemName.setText(" sample text based on position ");
    }

添加 ViewHolder 重要: 我们不应该为除 Viewholder 之外的视图对象设置任何标签目的

  • I faced same problem
  • Solved using below techninc
  • Reason : Adapter not Loaded Frequentlyy.
  • in Your Custom Adapter class add ViewHolder using Access Specifiers

    private static class ViewHolder {
    
            protected TextView itemName;
    
        }
    

In Get View method

    @Override

        public View getView(int position, View view, ViewGroup viewGroup) {

            // create a ViewHolder reference
            ViewHolder holder;

            //check to see if the reused view is null or not, if is not null then reuse it
            if (view == null) {
                holder = new ViewHolder();

                view = mLayoutInflater.inflate(R.layout.list_item, null);
                holder.itemName = (TextView) view.findViewById(R.id.list_item_text_view);

                // the setTag is used to store the data within this view
                view.setTag(holder);
            } else {
                // the getTag returns the viewHolder object set as a tag to the view
                holder = (ViewHolder)view.getTag();
            }
    // now Use Holder object toget Idss 

    holder.itemName.setText(" sample text based on position ");
    }

Important : And We should not set Any Tag for view object except Viewholder Object

拧巴小姐 2024-09-15 21:50:52

所以我想我在这里发现了真正的问题。当您为每一行动态设置布局参数时,您需要确保针对所有条件都执行此操作。我的问题是,如果它是第一行,我设置一个布局参数(如填充或边距等),但如果它是中间行,我没有明确设置这些参数,认为它只会使用膨胀的内容通过视图充气机。这解释了为什么当我每次放大视图时它都会起作用。这是之前和之后的内容。之后:

之前:

if (position == 0) {

            layoutParams.topMargin = uiHelper.getDip(15.0f);
            layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP,
                    RelativeLayout.TRUE);
            holder.actionMenu.setLayoutParams(layoutParams);

            holder.contentLayout.setBackgroundResource(R.drawable.top_row);

        } else if (position == posts.size() - 1) {
            holder.contentLayout
                    .setBackgroundResource(R.drawable.bottom_row);

            holder.contentLayout.setPadding(holder.contentLayout
                    .getPaddingLeft(),
                    holder.contentLayout.getPaddingTop(),
                    holder.contentLayout.getPaddingRight(),
                    holder.contentLayout.getPaddingBottom() +  uiHelper.getDip(10.0f));

        } else {
            holder.contentLayout
                    .setBackgroundResource(R.drawable.inner_row);
        }

之后:`

            layoutParams.topMargin = uiHelper.getDip(10.0f);
        holder.contentLayout.setPadding(holder.contentLayout
                .getPaddingLeft(),
                holder.contentLayout.getPaddingTop(),
                holder.contentLayout.getPaddingRight(),
                uiHelper.getDip(10.0f));
        if (position == 0) {

            layoutParams.topMargin = uiHelper.getDip(15.0f);
            layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP,
                    RelativeLayout.TRUE);

            holder.contentLayout.setBackgroundResource(R.drawable.top_row);

        } else if (position == posts.size() - 1) {
            holder.contentLayout
                    .setBackgroundResource(R.drawable.bottom_row);

            holder.contentLayout.setPadding(holder.contentLayout
                    .getPaddingLeft(),
                    holder.contentLayout.getPaddingTop(),
                    holder.contentLayout.getPaddingRight(),
                    uiHelper.getDip(20.0f));

        } else {

            holder.contentLayout
                    .setBackgroundResource(R.drawable.inner_row);

        }

        holder.actionMenu.setLayoutParams(layoutParams);

so i think i discovered the real issue here. when you set layout parameters on the fly for each row, you need to make sure you do it for all conditions. my problem was that if it was the first row, i set a layout param (like padding or margins etc), but then if it was a middle row, i didn't explicitly set those params thinking that it would just use what was inflated by the view inflater. This explains why it worked when i inflated the view each time. Here is a before & after:

BEFORE:

if (position == 0) {

            layoutParams.topMargin = uiHelper.getDip(15.0f);
            layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP,
                    RelativeLayout.TRUE);
            holder.actionMenu.setLayoutParams(layoutParams);

            holder.contentLayout.setBackgroundResource(R.drawable.top_row);

        } else if (position == posts.size() - 1) {
            holder.contentLayout
                    .setBackgroundResource(R.drawable.bottom_row);

            holder.contentLayout.setPadding(holder.contentLayout
                    .getPaddingLeft(),
                    holder.contentLayout.getPaddingTop(),
                    holder.contentLayout.getPaddingRight(),
                    holder.contentLayout.getPaddingBottom() +  uiHelper.getDip(10.0f));

        } else {
            holder.contentLayout
                    .setBackgroundResource(R.drawable.inner_row);
        }

AFTER:`

            layoutParams.topMargin = uiHelper.getDip(10.0f);
        holder.contentLayout.setPadding(holder.contentLayout
                .getPaddingLeft(),
                holder.contentLayout.getPaddingTop(),
                holder.contentLayout.getPaddingRight(),
                uiHelper.getDip(10.0f));
        if (position == 0) {

            layoutParams.topMargin = uiHelper.getDip(15.0f);
            layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP,
                    RelativeLayout.TRUE);

            holder.contentLayout.setBackgroundResource(R.drawable.top_row);

        } else if (position == posts.size() - 1) {
            holder.contentLayout
                    .setBackgroundResource(R.drawable.bottom_row);

            holder.contentLayout.setPadding(holder.contentLayout
                    .getPaddingLeft(),
                    holder.contentLayout.getPaddingTop(),
                    holder.contentLayout.getPaddingRight(),
                    uiHelper.getDip(20.0f));

        } else {

            holder.contentLayout
                    .setBackgroundResource(R.drawable.inner_row);

        }

        holder.actionMenu.setLayoutParams(layoutParams);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文