【问题标题】:same convertView instance is passed for visible views in CursorAdapter为 CursorAdapter 中的可见视图传递相同的 convertView 实例
【发布时间】:2013-03-05 19:54:55
【问题描述】:

我在 android 中自定义创建的 CursorAdapter 派生类有一个奇怪的问题:

我的 getView() 实现是在许多网站/Google 演讲中看到的直接教科书。但是,似乎对于不同的 positions(调用此方法的位置参数),此方法正在传递相同的 convertView 实例,即使在我看来, 这些应该引用不同的对象实例,因为它应该对应于 ListView 中的其他可见项,并且不应该在可见列表项的情况下重用相同的对象实例...

我已经删除了更新实际视图的实际部分,因为即使没有它,问题也会重现。

@Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder;

        Log.d("dd", "getView()");

        if (convertView == null) {
            Log.d("d", "convertview is null!");

            // create convertView from xml
            convertView = this.mInflater.inflate(R.layout.catalog_entry,
                    parent, false);

            // create the viewHolder
            viewHolder = new ViewHolder();

            viewHolder.name = (TextView) convertView
             .findViewById(R.id.gameName2);
             viewHolder.image = (ImageView) convertView
             .findViewById(R.id.gameImage);

            convertView.setTag(viewHolder);
        } else {
            Log.d("dd", "convertview is not null");
            viewHolder = (ViewHolder) convertView.getTag();
        }

        LinearLayout thisItem = (LinearLayout) convertView;
        Log.d("thisItem",
                "This Item is Index "
                        + position
                        + " "
                        + thisItem.toString()
                        + " "
                        + Integer.toHexString(System.identityHashCode(thisItem))
                        + "x: " + thisItem.getX() + " y: " + thisItem.getY());

        this.cur.moveToPosition((int) (getItemId(position) - 1));

        Log.d("dd", "End of getView()");
        return convertView;
    }

运行此代码会产生以下输出:

D/dd (27725): getView() D/d (27725): convertview 为空! D/thisItem(27725): 这个项目是索引 0 android.widget.LinearLayout@40fb5f70 40fb5f70x: 0.0 y: 0.0 D/dd
(27725): getView() D/dd 结束 (27725): getView() D/dd
(27725): convertview 不为空 D/thisItem(27725): This Item is Index 1 android.widget.LinearLayout@40fb5f70 40fb5f70x: 0.0 y: 0.0 D/dd
(27725): getView() D/dd 结束 (27725): getView() D/dd
(27725): convertview 不为空 D/thisItem(27725): This Item is Index 2 android.widget.LinearLayout@40fb5f70 40fb5f70x: 0.0 y: 0.0 D/dd
(27725): getView() D/dd 结束 (27725): getView() D/dd
(27725): convertview 不为空 D/thisItem(27725): This Item is Index 3 android.widget.LinearLayout@40fb5f70 40fb5f70x: 0.0 y: 0.0 D/dd
(27725): getView() D/dd 结束 (27725): getView() D/dd
(27725): convertview 不为空 D/thisItem(27725): This Item is Index 4 android.widget.LinearLayout@40fb5f70 40fb5f70x: 0.0 y: 0.0 D/dd
(27725): getView() D/dd 结束 (27725): getView() D/dd
(27725): convertview 不为空 D/thisItem(27725): This Item is Index 0 android.widget.LinearLayout@40fb5f70 40fb5f70x: 0.0 y: 0.0 D/dd
(27725): getView() D/dd 结束 (27725): getView() D/d
(27725):转换视图为空! D/thisItem(27725):这个项目是索引 1 android.widget.LinearLayout@40fb89f8 40fb89f8x: 0.0 y: 0.0 D/dd
(27725): getView() D/dd 结束 (27725): getView() D/d
(27725):转换视图为空! D/thisItem(27725):这个项目是索引 2 android.widget.LinearLayout@40fb9c48 40fb9c48x: 0.0 y: 0.0 D/dd
(27725): getView() D/dd 结束 (27725): getView() D/d
(27725):转换视图为空! D/thisItem(27725):这个项目是索引 3 android.widget.LinearLayout@40fbae98 40fbae98x: 0.0 y: 0.0 D/dd
(27725): getView() D/dd 结束 (27725): getView() D/d
(27725):转换视图为空! D/thisItem(27725):这个项目是索引 4 android.widget.LinearLayout@40fbc0e8 40fbc0e8x: 0.0 y: 0.0 D/dd
(27725):getView() 结束

一开始可以看出,对于每个位置(0到4),都在发送相同的View对象哈希...

【问题讨论】:

  • (请在代码块中发布堆栈跟踪,因为引号块不考虑换行符。)ListViews 在绘制布局之前经常调用getView() 多次,特别是如果您使用wrap_content 作为高度。
  • 他们是否多次调用getView,传递一次创建的convertView?即使是不同的数据位置?
  • 另外,据我所知,getView() 的目的是为特定的列表视图项创建一个视图。如果这涉及用一些图像/文本/等填充项目,我该如何应对每个特定项目可能多次调用它的事实?
  • 我假设这是简单启动应用程序的输出并且您没有滚动 ListView。我说的对吗?
  • @sam 这是正确的,但即使不滚动也会导致错误的行为。如果我将图像设置为列表视图项,则列表中的第一项会获得一堆不同的图片(因为在日志中看到,相同的实例在开始时用于一堆调用)。

标签: java android listview simplecursoradapter


【解决方案1】:

简而言之,将 ListView 的高度设置为 match_parent 或其他固定高度。

ListView 以你看到的“试运行”方式调用getView() 的原因有很多,最常见的原因是你使用了wrap_content 作为 ListView 的高度。 Android 必须膨胀一堆行来计算wrap_content 的高度,但它不能使用真实数据,因为这还不可用。所以适配器抛出这些最佳猜测。稍后,使用实际数据(重新)创建布局,这就是为什么您会看到每行创建两次。

CursorAdapter 也应该自己维护适当的行,你不需要这一行:

this.cur.moveToPosition((int)(getItemId(position) - 1));

【讨论】:

    【解决方案2】:

    Convertview 重用视图是正确的。 您可以删除所有 Convertview 部分,并确保它不会重复使用不需要的视图,并且您将获得所需的结果(以牺牲一些性能为代价......)。

    【讨论】:

      猜你喜欢
      • 2020-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多