title: Android AsyncTask with ListView containing Button onClickListener
body: <p>I have a listview which is filled with data form sqlitedatabase. A list-view element contains a TextView a Button and a Checkbox. Clicking on the Button shows a timepicker dialog. Accepting a time from the timepickerdialog starts an AsyncTask. There is always a new AsyncTask created when I click on the button.</p>
  
  <p>Now when I click on the seventh List-Item, the first list item is updated. There might be an error with the threads.</p>
  
  <p>the activity:</p>
  
  <pre><code>public class SettingsActivity extends Activity 
  {
      private static final String TAG = "SettingsActivity";
      private ReminderBusAdapter busAdapter;
      private List&lt;Reminder&gt; reminderGoalsList;
      private static final int TIME_PICKER_DIALOG = 1;
      private static final String TIME_FORMAT = "kk:mm";
      private Calendar mCalendar;
  
      // view elements
      TextView tvStatus;
      ListView listViewReminder;
  
      @Override
      protected void onCreate(Bundle savedInstanceState) 
      {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.settings);
  
          // fetch required data reminder
          busAdapter = new ReminderBusAdapter(this);
          loadSettingsData();
  
          // generate view
          displayView();
  
          mCalendar = Calendar.getInstance();
      }
  
      private void loadSettingsData() 
      {
          Log.i(TAG, "loadSettingsData");
          reminderGoalsList = new ArrayList&lt;Reminder&gt;();
          reminderGoalsList = busAdapter.receiveReminders();
  
          Iterator&lt;Reminder&gt; iter = reminderGoalsList.iterator();
          Log.i(TAG, "iterate through all Reminders fetched from db");
  
          int cnt = 0;
          while (iter.hasNext()) 
          {
              cnt++;
              Log.i(TAG, cnt + "] " + iter.next().toString());
          }
      }
  
      private void displayView() 
      {
          Log.i(TAG, "displayView");
          tvStatus = (TextView) findViewById(R.id.settingsTextView);
          listViewReminder = (ListView) findViewById(R.id.settingsListView);
          listViewReminder.setAdapter(new SettingsAdapter(this,
                              R.layout.settings_reminder_listview, reminderGoalsList));
      }
  
      @Override
      protected Dialog onCreateDialog(int id, Bundle b) 
      {
          switch (id) 
          {
              case TIME_PICKER_DIALOG:
                  return showTimePicker(b);
          }
          return super.onCreateDialog(id);
      }
  
      private Dialog showTimePicker(final Bundle b) 
      {
          TimePickerDialog timePicker = new TimePickerDialog(this, 0,
                          new TimePickerDialog.OnTimeSetListener() 
                          {
                              @Override
                              public void onTimeSet(TimePicker view, int hourOfDay, int minute) 
                              {
                                  mCalendar.set(Calendar.HOUR_OF_DAY, hourOfDay);
                                  mCalendar.set(Calendar.MINUTE, minute);
  
                                  Reminder rem = (Reminder) b.get("reminder");
                                  Log.i(TAG, rem.toString() + " got from adapter");
  
                                  SimpleDateFormat dateFormat = new SimpleDateFormat(TIME_FORMAT);
                                  String dateForTimeButton = dateFormat.format(mCalendar.getTime());
  
                                  rem.setTime(dateForTimeButton);
  
                                  new UpdateTimerByBtn().execute(new String[] 
                                                          {
                                                              rem.getTime(),
                                                              new String(Integer.toString(rem.getId())) 
                                                          });
                              }
                          }, mCalendar.get(Calendar.HOUR_OF_DAY),
                          mCalendar.get(Calendar.MINUTE), true);
          return timePicker;
      }
  
      class UpdateTimerByBtn extends AsyncTask&lt;String, Integer, String&gt; 
      {
          @Override
          protected String doInBackground(String... params) 
          {
              Log.i(TAG, "Starting AsyncTask " + "UpdateTimerByBtn new time="
                                               + params[0] + " from id= " + params[1]);
  
              busAdapter.updateReminder(params[0], Integer.parseInt(params[1])); 
              return "finish";
          }
  
          @Override
          protected void onPostExecute(String result) 
          {
              super.onPostExecute(result);
              loadSettingsData();
              displayView();
          }
      }
  }
  
  public class SettingsAdapter extends ArrayAdapter&lt;Reminder&gt; 
  {
      protected static final String TAG = "SettingsAdapter";
      private static final int TIME_PICKER_DIALOG = 1;
      private List&lt;Reminder&gt; arrayListReminders;
      private int layout;
      private Activity activity;
  
      public SettingsAdapter(Activity activity, int layout, List&lt;Reminder&gt; objects) 
      {
          super(activity, layout, objects);
  
          this.arrayListReminders = objects;
          this.layout = layout;
          this.activity = activity;
      }
  
      static class ViewHolder 
      {
          private TextView listReminderTextView;
          private Button listReminderTimeButton;
          private CheckBox listReminderCheckBox;
      }
  
      @Override
      public View getView(int position, View convertView, android.view.ViewGroup parent) 
      {
          final Reminder rem = arrayListReminders.get(position);
          View view = convertView;
          ViewHolder viewHolder = null;
  
          if (view == null) 
          {
              LayoutInflater layoutInflater = (LayoutInflater) getContext()
                                      .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
              view = layoutInflater.inflate(layout, parent, false);
          }
  
          if (view != null) 
          {
              viewHolder = new ViewHolder();
              viewHolder.listReminderTextView = (TextView) view.
                                          findViewById(R.id.list_reminder_day_textview);
  
              viewHolder.listReminderTimeButton = (Button) view
                                  .findViewById(R.id.settings_reminder_list_time_button);
  
              viewHolder.listReminderCheckBox = (CheckBox) view
                                  .findViewById(R.id.settings_reminder_list_checkbox);
  
              switch (rem.getId()) 
              {
                  case 1:
                      viewHolder.listReminderTextView.setText(R.string.Mo);
                      break;
                  case 2:
                      viewHolder.listReminderTextView.setText(R.string.Di);
                      break;
                  case 3:
                      viewHolder.listReminderTextView.setText(R.string.Mi);
                      break;
                  case 4:
                      viewHolder.listReminderTextView.setText(R.string.Do);
                      break;
                  case 5:
                      viewHolder.listReminderTextView.setText(R.string.Fr);
                      break;
                  case 6:
                      viewHolder.listReminderTextView.setText(R.string.Sa);
                      break;
                  case 7:
                      viewHolder.listReminderTextView.setText(R.string.So);
                      break;
                  default:
                      break;
              }
  
              viewHolder.listReminderTimeButton.setText(rem.getTime() + " " + "Uhr");
  
              viewHolder.listReminderTimeButton
                        .setOnClickListener(new OnClickListener() 
                          {
                              @Override
                              public void onClick(View v) 
                              {
                                  Log.i(TAG, "clicked " + rem.toString());
  
                                  Bundle bundle = new Bundle();
                                  bundle.putSerializable("reminder", rem);
  
                                  ((SettingsActivity) activity).showDialog(TIME_PICKER_DIALOG, bundle);
                              }
                          });
  
              viewHolder.listReminderCheckBox.setChecked(rem.isEnabled() ? true : false);
          }
          return view;
      };
  }
  </code></pre>
  
  <hr>
  
  <p>Thanks for your help - I changed the getView Method and started debugging everything.</p>
  
  <p>I think the problem is where the TimePicker Dialog is created in the Activity.</p>
  
  <pre><code>private Dialog showTimePicker(final Bundle b) 
  {
      TimePickerDialog timePicker = new TimePickerDialog(this, 0,
                          new TimePickerDialog.OnTimeSetListener() 
                          {
                              @Override
                              public void onTimeSet(TimePicker view, int hourOfDay,int minute) 
                              {
                                  mCalendar.set(Calendar.HOUR_OF_DAY, hourOfDay);
                                  mCalendar.set(Calendar.MINUTE, minute);
  
                                  Reminder rem = (Reminder) b.get("reminder");
                                  Log.i(TAG, rem.toString() + " got from adapter");
  
                                  SimpleDateFormat dateFormat = new SimpleDateFormat(TIME_FORMAT);
                                  String dateForTimeButton = dateFormat.format(mCalendar.getTime());
  
                                  rem.setTime(dateForTimeButton);
                                  Log.i(TAG, rem.toString());
                                  new UpdateTimerByBtn().execute(new String[] {
                                              rem.getTime(),
                                              new String(Integer.toString(rem.getId())) 
                                          });
                              }
                          }, mCalendar.get(Calendar.HOUR_OF_DAY)
                          , mCalendar.get(Calendar.MINUTE), true);
      return timePicker;
  }
  </code></pre>
  
  <p>I get the required object from the Bundle. This Bunlde is final and never changes when I transfer a new Bundle from the adapter to the activity. When I click on another Button the same Dialog is shown (with the same value) and the OnTimeSetListener is executed with that final bundle. Is there a way to handle dialiogs form adapters? Should I create one Dialog for each row in the ViewHolder?</p>