【问题标题】:Why isn't an Adapter with cached buttons working as expected in Android?为什么带有缓存按钮的适配器在 Android 中不能按预期工作?
【发布时间】:2012-04-15 23:18:05
【问题描述】:

Edit3:将代码交换为完整的可运行测试用例。

Edit2:添加了一些在五秒后更新按钮数量的代码。发生这种情况时,无论您使用什么布局,按钮都无法点击。

Edit1:这似乎取决于用于 ListView 的布局。我会进一步调查。

我想创建一次按钮,即缓存它们。由于各种原因,我无法使用提供的 convertView 并对其进行编辑(每一行最终都会包含几个组件,它们都是由另一个框架创建的)。

如果我创建一个如下所示的适配器,这似乎非常合理并且 imo 应该可以工作,那么只有在 ListView 之外并被滚动回的按钮是可点击的。

似乎按钮的可点击区域在首次显示时设置不正确。谁能解释一下为什么?

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.*;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Timer;
import java.util.TimerTask;

public class TestActivity extends Activity
{
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        final ListView listView = new ListView(this);

        final ArrayList<View> cachedButtons = new ArrayList<View>(Arrays.asList(new View[20]));

        listView.setAdapter(new BaseAdapter() {
            public View getView(int position, View convertView, ViewGroup parent)
            {
                if (cachedButtons.get(position) == null) {
                    Button b = new Button(parent.getContext());
                    b.setText("Button " + position);
                    b.setClickable(true);
                    cachedButtons.set(position, b);
                }
                return cachedButtons.get(position);
            }

            public int getCount() { return cachedButtons.size(); }
            public Object getItem(int position) { return null; }
            public long getItemId(int position) { return position; }
        });

        // Add a new button after five seconds
        new Timer().schedule(new TimerTask() {
            public void run()
            {
                runOnUiThread(new Runnable() {
                    public void run()
                    {
                        cachedButtons.addAll(Arrays.asList(new View[1])); // Add one more
                        ((BaseAdapter) listView.getAdapter()).notifyDataSetChanged();
                        Toast.makeText(listView.getContext(), "Now you can't press the buttons anymore", 0).show();
                    }
                });
            }
        }, 5000);

        // Doesn't work with these lines
        LinearLayout layout = new LinearLayout(this);
        layout.addView(listView);
        setContentView(layout);

        // Works with this, so no Layout works.
        //setContentView(layout);
    }
}

【问题讨论】:

  • 我已经测试了您的代码并且所有按钮都是可点击的。也许这不是您的全部代码?此外,应使用适配器将数据绑定到 ListView 而不是视图。
  • 好的,我做了更多的测试。如果按钮被改变,我认为边界,一切都变得不可点击。一些布局管理器会更定期地执行此操作,而有些则不会。如果您添加我在原始帖子底部添加的代码,则在我的测试用例中,按钮在五秒钟后变得不可点击。

标签: android listview click


【解决方案1】:

我认为 Android 正在重用您的视图,因此会给您带来问题。我建议您使用视图持有者。它是一个为您保存视图的静态类。请参阅 this 教程

【讨论】:

  • 谢谢。好读。我觉得奇怪的是,它未经我的许可重用了我的视图。特别是因为我没有使用 convertView。我必须认为 Swing 的 API 在这方面要好得多。
  • 这是因为 android 的内存系统很紧,它重用内存效率更高。
  • 是的,但是在 Swing 的模型中,您可以只使用一个 View,这样会更好。
  • 在摇摆中,您没有内存限制,但由于它在移动设备上您有内存限制。即使 Java 核心也已被修改,并且在引擎盖下并不完全相同。
【解决方案2】:

答案很简单,却让我想了好几个小时。只需覆盖 getItemViewType ,视图将不会被回收。至少它现在似乎有效。我仍然觉得 JavaDocs 对此感到困惑。

public int getItemViewType(int position)
{
    return AdapterView.ITEM_VIEW_TYPE_IGNORE;
}

【讨论】:

  • 谢谢,很好的发现。如果您可以保证少量项目(少于一百个左右),这可能是一个令人满意的解决方案。如果有人知道更好,请告诉我。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-30
  • 2020-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多