Android: Button within ListView not receiving onClick events
<p>I am making a date picker activity that looks like a scrolling 30 day month/calendar (think Outlook calendar).  The date picker contains a ListView (for scrolling) of MonthView views each of which is a TableView of the individual days.  Each individual day in the MonthView is a button.  When the MonthView is instantiated I walk each of the days (buttons) and attach a click listener:</p>

<pre><code>final Button b = getButtonAt(i);
b.setOnClickListener(new OnClickListener()
{
      @Override
      public void onClick(View v) {
            setSelectedDate(buttonDayClosure, b);
      }
});
</code></pre>

<p>setSelectedDate does a variety of things, but it also turns the button's background to yellow to signify the date is selected.</p>

<p>On my emulator, everything works as you would expect.  Activity comes up, you press a day, the day turns yellow.  No problems.</p>

<p>However, on some of my peer's emulators and on physical devices when you touch a day nothing happens... until you scroll the ListView... and then all of a sudden the selected day turns yellow.  So, for example, you touch "the 3rd" and then nothing happens.  Wait a few seconds and then scroll the ListView (touching an area of the calendar that is NOT the 3rd) and as soon as ListView scrolls the 3rd magically turns yellow.</p>

<p>On my peer emulators that show this behavior, I can set a breakpoint on the fist line of onClick and I see that the BP is in fact not hit until the ListView is scrolled.</p>

<p>This behavior doesn't make any sense to me. I would expect the onClick behavior to be unrelated to the encapsulating View's scrolling efforts.</p>

<p>Any thoughts on why this might be the case and how I can rectify the situation so that onClicks always happen immediately when the button is touched?</p>

<p>Thanks.</p>

<p>Post Scriptus:  ArrayAdapter and ListView code requested:</p>

<pre><code>public class MonthArrayAdapter extends ArrayAdapter&lt;Date&gt; {

    private MonthView[] _views; 

    private Vector&lt;Procedure&lt;Date&gt;&gt; _dateSelectionChangedListeners = new Vector&lt;Procedure&lt;Date&gt;&gt;();

    public MonthArrayAdapter(Context context, int textViewResourceId, Date minSelectableDay, Date maxSelectableDay) {
        super(context, textViewResourceId);
        int zeroBasedMonth = minSelectableDay.getMonth();
        int year = 1900 + minSelectableDay.getYear();

        if(minSelectableDay.after(maxSelectableDay))
        {
            throw new IllegalArgumentException("Min day cannot be after max day.");
        }

        Date prevDay = minSelectableDay;
        int numMonths = 1;
        for(Date i = minSelectableDay; !sameDay(i, maxSelectableDay); i = i.addDays(1) )
        {
            if(i.getMonth() != prevDay.getMonth())
            {
                numMonths++;
            }
            prevDay = i;
        }

        _views = new MonthView[numMonths];

        for(int i = 0; i&lt;numMonths; i++)
        {
            Date monthDate = new Date(new GregorianCalendar(year, zeroBasedMonth, 1, 0, 0).getTimeInMillis());
            Date startSunday = findStartSunday(monthDate);
            this.add(monthDate);
            _views[i] = new MonthView(this.getContext(), startSunday, minSelectableDay, maxSelectableDay);

            zeroBasedMonth++;
            if(zeroBasedMonth == 12)
            {
                year++;
                zeroBasedMonth = 0;
            }
        }

        for(final MonthView a : _views)
        {
            a.addSelectedDateChangedListener(new Procedure&lt;MonthView&gt;()
            {
                        @Override
                    public void execute(MonthView input) {

                        for(final MonthView b: _views)
                        {
                            if(a != b)
                            {
                                b.clearCurrentSelection();
                            }
                        }

                        for(Procedure&lt;Date&gt; listener : _dateSelectionChangedListeners)
                        {
                            listener.execute(a.getSelectedDate());
                        }
                    }
            });
        }




    }

    void addSelectedDateChangedListener(Procedure&lt;Date&gt; listener)
    {
        _dateSelectionChangedListeners.add(listener);
    }

    private boolean sameDay(Date a, Date b)
    {
        return a.getYear() == b.getYear() &amp;&amp; a.getMonth() == b.getMonth() &amp;&amp;
               a.getDate() == b.getDate();
    }

    @Override
    public View getView (int position, View convertView, ViewGroup parent)
    {
        return _views[position];
    }


    private Date findStartSunday(Date d)
    {
        return d.subtractDays(d.getDay());
    }

    public void setSelectedDate(Date date)
    {
        for(MonthView mv : _views)
        {
            mv.setSelectedDate(date);
        }
    }



}
</code></pre>

<p>and</p>

<pre><code>public class DatePicker extends ActivityBase {

    public static final String CHOSEN_DATE_RESULT_KEY = "resultKey";

    public static final String MIN_SELECTABLE_DAY = DatePicker.class.getName() + "MIN";

    public static final String MAX_SELECTABLE_DAY = DatePicker.class.getName() + "MAX";

    private static final String SELECTED_DATE = UUID.randomUUID().toString();

    private long _selectedDate = -1;

    private MonthArrayAdapter _monthArrayAdapter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Date now = new Date();

        Bundle inputs = this.getIntent().getExtras();

        long min = inputs.getLong(MIN_SELECTABLE_DAY, 0);

        Date minSelectableDate;
        if(min == 0)
        {
            minSelectableDate = new Date(now);
        }
        else
        {
            minSelectableDate = new Date(min);
        }
        Log.i(DatePicker.class.getName(), "min date = " + minSelectableDate.toString());
        long max = inputs.getLong(MAX_SELECTABLE_DAY, 0);

        Date maxSelectableDate;
        if(max == 0)
        {
            maxSelectableDate = new Date(now.addDays(35).getTime());
        }
        else
        {
            maxSelectableDate = new Date(max);
        }


        setContentView(R.layout.date_picker);

        Button doneButton = (Button) findViewById(R.id.DatePickerDoneButton);

        if(doneButton == null)
        {
            Log.e(this.getClass().getName(), "Could not find doneButton from view id.");
            finish();
            return;
        }

        doneButton.setOnClickListener(new OnClickListener()
        {
            @Override
            public void onClick(View v) {
                Intent result = new Intent();
                result.putExtra(CHOSEN_DATE_RESULT_KEY, _selectedDate);
                setResult(RESULT_OK, result);
                finish();
            }
        });

        Button cancelButton = (Button) findViewById(R.id.DatePickerCancelButton);

        if(cancelButton == null)
        {
            Log.e(this.getClass().getName(), "Could not find cancelButton from view id.");
            finish();
            return;
        }

        cancelButton.setOnClickListener(new OnClickListener()
        {
            @Override
            public void onClick(View v) {
                setResult(RESULT_CANCELED, null);
                finish();
            }
        });

        ListView lv = (ListView)findViewById(R.id.DatePickerMonthListView);
        lv.setDividerHeight(0);


        _monthArrayAdapter = 
            new MonthArrayAdapter(this, android.R.layout.simple_list_item_1, minSelectableDate, maxSelectableDate);

        _monthArrayAdapter.addSelectedDateChangedListener(new Procedure&lt;Date&gt;()
                {

                    @Override
                    public void execute(Date input) {
                        _selectedDate = input.getTime();

                    }


                });

       lv.setAdapter(_monthArrayAdapter);
    }

    @Override 
    public void onRestoreInstanceState(Bundle savedInstanceState)
    {
        if(savedInstanceState.containsKey(SELECTED_DATE))
        {
            _selectedDate = savedInstanceState.getLong(SELECTED_DATE);
            _monthArrayAdapter.setSelectedDate(new Date(_selectedDate));
        }
    }

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState)
    {
        savedInstanceState.putLong(SELECTED_DATE, _selectedDate);
    }

 }
</code></pre>
