0

我正在为列表视图使用自定义列表适配器。我在列表视图中定义了一个按钮并且点击事件有效,但问题是一旦滚动列表,它将多个视图绑定到同一个按钮。因此,在单击按钮时,会触发与每个关联视图关联的事件。

我该如何处理?

4

2 回答 2

0

Stuart 是完全正确的 - 问题是 ListView 中的视图被重用(以避免创建不同的对象),并且由于列表的不同部分是可见的,对于一个新位置,您可以获得任何不再使用的视图。所以你的代码应该正确处理这个问题。我想补充一点,monodroid 中 Java 对象的垃圾收集效果不好。根据我的经验,创建大量从 Java.Lang.Object 派生的对象会使应用程序崩溃。所以:

  1. 为每个新行创建新视图将很快使应用程序崩溃,因此您必须尽可能重用 convertView。

  2. Tag 具有 Java.Lang.Object 类型,因此 WrappedPosition 应该派生自 Java 对象。这意味着您应该重用相同的实例,而不是每次都创建新实例。

  3. 如果您将点击处理程序移动到单独的方法,您可以在订阅之前取消订阅,因此您不需要任何逻辑“如果视图为空”。

如果您觉得它有用,我可能会在此处发布解释其工作原理的代码示例。最初不要发布它,因为它很大:)

于 2012-12-02T19:17:31.557 回答
0

我猜你误解了列表的工作原理——尤其是 convertView 的使用方式。

Android 中的 ListViews 虚拟化 UI - 就像 WP 中的 ListBoxes 和 iOS 中的 UITableViews 一样

这意味着,如果底层列表有 1000 个项目,但屏幕上只有 10 个项目的空间,那么列表将只创建 10 个“容器”来显示列表项目,并使用这些容器仅显示内容在当时看来。

它这样做的方式是通过适配器 - 特别是通过 GetView 回调 - 它将 convertView 作为其参数之一。

如果您选择在 GetView 实现中创建新视图,则可以在回调中订阅新事件...

如果您选择在 GetView 实现中使用 convertView,那么您不应该在回调中订阅新事件 - 除非先取消订阅旧事件。

例如,我猜你的代码目前正在执行类似这样的伪操作:

 public View GetView(int pos, View convertView)
 {
     TextView toShow = convertView as TextView;
     if (toShow == null)
     {
        toShow = new TextView();
     }

     toShow.Text = "Item at position " + i;
     toShow.Click += (s,e) => {
         // do something
     };

     return toShow;
 }

代码的问题是您会经常订阅 Click ...您需要通过以下方式解决它:

 public View GetView(int pos, View convertView)
 {
     TextView toShow = convertView as TextView;
     if (toShow == null)
     {
        toShow = new TextView();
        toShow.Click += (s,e) => {
            // do something with the position embedded in toShow.Tag
        };
     }

     toShow.Text = "Item at position " + i;
     toShow.Tag = new WrappedPosition(i);
     return toShow;
 }

反正这是我的猜测:)

于 2012-11-09T16:35:50.363 回答