Android BaseAdapter: 在 getView() 重新进入时 convertView 为 null

3
我正在按照 http://bartinger.at/listview-with-sectionsseparators/ 上描述的技术构建一个具有分组节的 ListView。但我想通过重复使用 convertView 来扩展它以供非节项使用。然而,我发现每次进入 getView() 方法时 convertView 变量都为 null。有人能解释一下这是为什么吗?
ViewHolder holder;
final ListViewItem item = items.get(position);

if (item.isSection()) {
    Section section = (Section)item;

    convertView = inflater.inflate(R.layout.section, null);
    TextView title = (TextView) convertView.findViewById(R.id.section_title);
    title.setText(section.title);
} else {
    if (convertView == null) {
        Log.d("Adapter", "convertView was null");
    }

    Server server = (Server)item;

    convertView = inflater.inflate(R.layout.server_row, null);
    holder = new ViewHolder();
    holder.serverName = (TextView) convertView.findViewById(R.id.server_name);
    holder.serverStatusIcon = (ImageView)convertView.findViewById(R.id.server_status_icon);
    convertView.setTag(holder);

    holder.serverName.setText(server.name);
}

return convertView;

列表已经被成功创建并显示,包含了部分和非部分项目。

你在哪里使用这个?是在 ListView、ExpandableListView、Gallery、Spinner 等控件中吗? - K-ballo
如果没有可重用的视图,Android 将会将 null 传递给 convertView 参数。 - Zar E Ahmer
3个回答

5

您是否正确实施了

getItemViewType (int position) ?

从Android的文档中可以看到:

返回值

一个表示View类型的整数。如果一个View可以在getView(int, View, ViewGroup)中转换为另一个View,则两个View应该共享相同的类型。注意:整数必须在0到getViewTypeCount() - 1的范围内。也可以返回IGNORE_ITEM_VIEW_TYPE。

因此,可能convertView始终为空,因为适配器不知道哪些项目属于一起,因此它不知道要回收哪些项目...

尝试这个:

@Override
public int getItemViewType(int position) {
    if (((MyItem)getItem(position)).isHeader()) {
        return 1;
    } else {
        return 0;
    }
}

@Override
public int getViewTypeCount() {
    return 2;
}

您在getItemViewType中返回的索引仅是将标题和非标题分组的标识符。
在这种情况下,您需要在模型项中实现一个名为“isHeader”的方法(或类似方法)。

我已经查看了API中的这些方法,但它们并没有说明是必需的。我期望收到上次返回的任何视图。 然而,我确实添加了这些方法(如您在帖子中所见),但仍然收到空的convertViews。 - Marc
我猜想你可能得不到上次的视图,因为你很可能仍在使用它(列表中的上一个元素)。框架决定何时向你传递“旧”视图进行回收利用。现在,如果你使用了不同类型的项,框架就不能向你传递任何视图,它必须知道被回收(旧)视图与你正在创建的视图兼容。而这些方法就是帮助实现这一点的。它们不是必需的,因为如果你不实现它们,它不会破坏任何东西。但是你将无法回收视图,并且始终会得到空值。 - User
(这只是我的理论)。但为什么不尝试实现一下,看看是否有帮助呢? - User
这个理论并不正确,但它确实帮助我得出了答案(发布)。谢谢! - Marc

0

我刚刚遇到了一个我创建的GridView的问题。当我尝试将新充气的视图分配给convertView时,出现了问题。我采用的通用结构是

public View getView(int position, @Nullable View convertView, ViewGroup parent) {

    View newView = null;
    TextView someText;

    // Test to see if there is already a view, if not create one, else use what is
    // already existant in convertView
    if (null == convertView) {
        // inflate your view type into newView here
        newView = myInflater.inflate(R.layout._________);

        // Get all of your subviews you wish to edit here from newView
        someText = (TextView)newView.findViewById(R.id._______);
    }else{
        // Get all of your subviews you wish to edit here from convertView
        someText = (TextView)convertView.findViewById(R.id._______);
    }

    // Perform all re-alignments, view layouts etc... here

    // Perform all updating of subviews data here

    // Return structure
    if (null == convertView) {
        return newView;
    } else {
        return convertView;
    }
}

希望这能有所帮助!

如果我理解正确,你是在说问题可能是需要在第一次使用时使用一个自声明的View变量。我测试了一下,似乎没有任何影响。我似乎可以无问题地将其展开到convertView中。但是还是谢谢你的建议。 - Marc

0

感谢Ixx提醒我:我没有注意到的是,我的列表太短了,它从未填满屏幕,因此没有进行回收。

为了完整起见,我将补充说明:如果您创建多个视图类型,则getView()会返回convertView - 即使您没有覆盖getItemViewType()和getViewTypeCount() - 根据它们的默认实现(如下所示)。当然,这可能不是您想要的行为。

public int getItemViewType(int position) {
    return 0;
}

public int getViewTypeCount() {
    return 1;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接