为什么带有缓存按钮的适配器不能像Android中预期的那样工作?

时间:2012-04-14 10:35:06

标签: android listview click

编辑3:为完整的可运行测试用例交换代码。

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);
    }
}

2 个答案:

答案 0 :(得分:2)

我认为Android会重复使用您的观点,因此会导致您出现问题。我建议您使用视图持有者。它是一个静态类,可以为您保存视图。请参阅this教程

答案 1 :(得分:2)

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

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