【问题标题】:ListView getChildAt returning null for visible childrenListView getChildAt 为可见的孩子返回 null
【发布时间】:2011-07-20 18:26:22
【问题描述】:

我从 listview/getChildAt 方法中得到了一些奇怪的行为。

我有一个 HashSet,iconsToUpdate,是数据库中已更改的图标。我想遍历可见行以查看是否需要更新它们的任何图标以反映新图标。我不需要测试当前不在视图中的图标,因为它们会在渲染时正确绘制。

我的问题是 getChildAt 似乎不应该返回 null。我知道 getChildAt 只能返回当前可见的视图,但它为某些可见行返回 null。

这是我在可见行上迭代的代码:

Logger.debug("First visible index: " + f_listView.getFirstVisiblePosition());
Logger.debug("Last visible index: " + f_listView.getLastVisiblePosition());
for (int i = f_listView.getFirstVisiblePosition(); i <= f_listView.getLastVisiblePosition(); i++) {
    String tag = "asdf"; // Remove when bug is fixed.
    if (f_listView == null) {
        Logger.debug("f_listView is null");
    } else if (f_listView.getChildAt(i) == null) {
        Logger.debug("Child at index " + i + " is null");
    } else {
        tag = (String) f_listView.getChildAt(i).getTag();
        Logger.debug("Successful at index " + i + ", tag is: " + tag);
    }
    if (iconsToUpdate.contains(tag)) {
        setIcon(i, f_aim.getInHouseIcon(tag));
    }
}

这是与此循环运行相对应的日志:

D/...: First visible index: 3
D/...: Last visible index: 8
D/...: Successful at index 3, tag is: ...
D/...: Successful at index 4, tag is: ...
D/...: Successful at index 5, tag is: ...
D/...: Child at index 6 is null
D/...: Child at index 7 is null
D/...: Child at index 8 is null

应该注意的是,第一个和最后一个可见索引被正确报告,因为我在运行它时正在查看第 3-8 行。第 6、7、8 行正在正确渲染。如果它们为空,它们如何显示?

另外,我不知道这是否重要,但是当我在列表视图的顶部时,第 5 行是最后一个可见行。

任何关于为什么这些行被返回为 null 的信息将不胜感激。

谢谢!

【问题讨论】:

    标签: android listview null


    【解决方案1】:

    listView.getChildAt(i) 适用于 0 是第一个可见行, (n-1) 是最后一个可见行(其中 n 是您看到的可见视图数)。

    获取最后/第一个可见返回您拥有的 dataAdapter 中的位置。因此,由于您从位置 3 开始,看起来像 6 个可见视图,所以当您获得位置 6-8 时,您将获得空值。

    在您的示例中,getChildAt(0) 将返回位置 3。我通常会将位置存储在视图中,以便稍后在需要值时查找 dataAdapter。

    我认为你的 for 循环应该是这样的:

    for (int i = 0; i <= f_listView.getLastVisiblePosition() - f_listView.getFirstVisiblePosition(); i++) 
    

    希望这会有所帮助。

    【讨论】:

    • 酷,很高兴我能帮上忙。如果可以的话,也请接受,我真的很喜欢获得积分:)
    • 啊哈!谢谢。如果文档明确说明 getChildAt(i) 使用 VISIBLE 位置而不是逻辑位置,将会很有用。本来可以省下不少头发的。
    • 没错,这在文档中没有描述。 @CNick:对此有任何参考吗?
    • 我尝试了同样的 for 循环,但它返回了 null。对此有什么想法吗?
    • 哇,你修复了一个我整整半天都在研究的错误
    【解决方案2】:

    试试

    f_listView.getChildAt(positionOfChildYouWantGet - f_listView.getFirstVisiblePosition());
    

    【讨论】:

    • 谨慎回答,
    【解决方案3】:

    当您调用listView1.getLastVisiblePosition()listView1.getFirstVisiblePosition() 时,listview 返回列表视图中部分可见的项目的位置。例如,第一项可能是半可见的,而最后一项可能是半可见的。在这种情况下,即使您可以在列表视图中看到该项目的一部分,但适配器尚未为该项目调用 getView() 函数,因此该项目仍被视为 null。

    【讨论】:

    • 谁能确认这是否属实?
    【解决方案4】:

    在我的情况下,我有一个 listView 并且第一项是完全可见的,但是当我这样做时 getFirstVisiblePosition() 结果是 1 !

    当我滚动并让第一个项目半可见然后我的 getView 显示 getFirstVisiblePosition() 为 0 时,它变得更加奇怪。

    这是我的代码:

    public View getView(final int position, View convertView, final ViewGroup parent) {
            row = convertView;
            final AtomPaymentHolder holder = new AtomPaymentHolder();
    
            LayoutInflater inflater = ((Activity) context).getLayoutInflater();
            row = inflater.inflate(layoutResourceId, parent, false);
            row.setTag(items.get(position));
            holder.songitem = items.get(position);
            final int firstPosition = MainActivity.listviewSong.getFirstVisiblePosition() - MainActivity.listviewSong.getHeaderViewsCount(); 
            final int lastPosition = MainActivity.listviewSong.getLastVisiblePosition();
    
            if(MusicService.indexService>= firstPosition && MusicService.indexService<= lastPosition){
                MainActivity.listviewSong.getChildAt(MusicService.indexService-firstPosition).setBackgroundColor(getContext().getResources().getColor(R.color.pressed_color));
            }
    

    (当我选择下一个项目并滚动时,效果很好)

    【讨论】:

      【解决方案5】:

      它们可能是部分可见的。但是,当 getView() 尝试回收视图时,它会变得完全可见,其他视图会将它们视为 null。例如,如果您滚动列表并且顶部项目部分可见而底部部分可见,那么这些是空值,但您仍然可以看到它们。

      【讨论】:

      • 嗯,好吧,所有第 3-8 行都是完全可见的。不能有三个连续的部分可见的行,所以我认为这里还有更多事情要做。不过感谢您的回复!
      • 尝试从 i=0 开始?并检查输出
      【解决方案6】:

      我在 OnListItemClickListener() 中尝试过,但失败了。最后,我在我的自定义适配器中对列表视图进行了一些修改。在 getView() 中,我将 clickListener 应用于我经常添加到列表中的项目。 n 在那里完成所有必需的功能。这是我的代码,我在列表 n 中添加图像视图,因此在 imageview 上应用侦听器。

      我认为它会帮助那些想要在特定列表项被选中时更改颜色的人。去吧。。

      在自定义Adapter的getView()中 // - - - - - - - - - - - - - - - - -代码 - - - - - - - ----------------------------------------

      LayoutInflater inflater = (LayoutInflater) 上下文 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

      View rowView = inflater.inflate(R.layout.icon_image_layout, parent, false); ImageView imageView = (ImageView) rowView.findViewById(R.id.Icon_ImageView); imageView.setClickable(true); final int pos=position; imageView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub // TODO Auto-generated method stub try{ if(previous_view!=null) previous_view.setBackgroundColor(Color.WHITE); }catch (Exception e) { System.out.println("Exception Occurs Previous View"); } v.setBackgroundColor(Color.RED); MainActivity.imageView.setImageResource(MainActivity.Image_Name[pos]); previous_view=v; return false; } });

      【讨论】:

        【解决方案7】:

        我知道这是很老的帖子。但我之所以回答是因为人们仍在寻找解决 ListView getChildAt() 空指针异常的方法。

        这是因为 ArrayApdater 正在移除和回收由于高度而在 ListView 上尚不可见的视图。因此,如果您有 10 个项目视图,并且 ListView 一次可以显示 4 - 5 个:

        Adapter REMOVE 位置 5 到 9 的 item 视图,这样任何adapter.getChildAt(5... to 9) 的尝试都会导致空指针异常

        适配器还会回收项目视图,因此当您向下滚动到 5 到 9 时,您在位置 3 上所做的任何引用都会丢失,您在位置 3 上所做的任何输入(EditText、复选框等)也会丢失.) 将在您向下滚动到 5 到 9 时被回收,稍后将在另一个位置(例如位置 1、2 或 3 等)以相同的值重复使用

        我发现控制它的唯一方法是忘记获取视图并拥有:

        属性HashMap&lt;Integer, ImageView&gt; iconViews 或您想要用于处理列表中每个项目的值的任何类型。对于item-&gt;getId()position 等项目,第一种类型必须是唯一的。在构造函数中使用new HashMap&lt;&gt;() 对其进行初始化; 在 getViews 中制作 iconViews.put(position, iconView); 防止 Adapter 使用回收的 convertView,删除条件 if(convertView == null) 以便适配器总是膨胀一个全新的视图实例。因为视图实例每次都是新的,所以每次都必须从 HashMap 中设置值,就像它已经包含键 if(iconViews.containsKey(position)){iconView = iconViews.get(position))}; 一样。在这种情况下,可能没有大量的项目,因此平滑滚动不是必须的。

        最后创建公共方法以通过 item-&gt;getId() 整数作为参数获取适配器之外的值。例如:public ImageView getIconViewAt(int position) { return iconViews.get(position); }。然后从适配器中选择项目将很容易

        通过我的answer 了解更多信息。

        【讨论】:

          【解决方案8】:

          不是因为你在说吗

          f_listView.getChildAt(i) 
          

          你应该在那个位置检索项目?

          f_listView.getItemAtPosition(i) 
          

          【讨论】:

          • 我认为不是。我相信 getItemAtPosition 获取该行的数据(来自适配器),而不是视图
          • 是的,steelbytes。在 CursorAdapter 的情况下,它返回光标。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-10-02
          • 1970-01-01
          • 1970-01-01
          • 2017-01-16
          • 1970-01-01
          • 2012-01-04
          • 1970-01-01
          相关资源
          最近更新 更多