Edit3: Exchanged the code for a complete runnable test case.
Edit2: Added some code that updates the number of buttons after five seconds. When this happens the buttons becomes unclickable no matter what layout you use.
Edit1: It seems this is depending on the Layout used for the ListView. I will investigate further.
I want to create the buttons once, i.e. cache them. I can't use the provided convertView and edit it for various reasons (every row will in the end contain a couple of components, all created by another framework).
If I create an Adapter like below, which seems very reasonable and imo should work, only buttons that have been outside the ListView, and are scrolled back in, are clickable.
It seems the button's clickable area isn't set correctly on first display. Can anyone explain why?
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);
}
}
I think Android is reusing your views so that is causing you problems .I suggest you use a view holder .It is a static class that holds the view for you.See this tutorial
The answer was quite simple, yet eluded me for many hours. Just override getItemViewType and the views won't be recycled. At least it seems to work for now. I still find the JavaDocs confusing on this.