1

J'ai un listview qui est rempli avec le formulaire de données sqlitedatabase. Un élément de vue liste contient un bouton TextView et une case à cocher. Cliquez sur le bouton pour afficher une boîte de dialogue Timepicker. Accepter une heure à partir du timepickerdialog démarre une asyncTask. Il y a toujours une nouvelle asyncTask créée lorsque je clique sur le bouton. Maintenant, lorsque je clique sur le septième élément de la liste, le premier élément de la liste est mis à jour. Il peut y avoir une erreur avec les threads.Android AsyncTask avec ListView contenant Button onClickListener

l'activité:

public class SettingsActivity extends Activity 
{ 
    private static final String TAG = "SettingsActivity"; 
    private ReminderBusAdapter busAdapter; 
    private List<Reminder> 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<Reminder>(); 
     reminderGoalsList = busAdapter.receiveReminders(); 

     Iterator<Reminder> 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<String, Integer, String> 
    { 
     @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<Reminder> 
{ 
    protected static final String TAG = "SettingsAdapter"; 
    private static final int TIME_PICKER_DIALOG = 1; 
    private List<Reminder> arrayListReminders; 
    private int layout; 
    private Activity activity; 

    public SettingsAdapter(Activity activity, int layout, List<Reminder> 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; 
    }; 
} 

Merci pour votre aide - j'ai changé la méthode getView et tout a commencé le débogage.

Je pense que le problème est l'endroit où la boîte de dialogue TimePicker est créée dans l'activité.

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

Je reçois l'objet requis de l'ensemble. Ce Bunlde est final et ne change jamais lorsque je transfère un nouvel ensemble de l'adaptateur à l'activité. Lorsque je clique sur un autre bouton, la même boîte de dialogue s'affiche (avec la même valeur) et OnTimeSetListener est exécuté avec cet ensemble final. Y at-il un moyen de gérer les adaptateurs de formulaire dialiogs? Dois-je créer un dialogue pour chaque ligne dans le ViewHolder?

Répondre

1

Cela ressemble à quelque chose ne va pas avec votre méthode getView dans la classe SettingsAdapter. Tout d'abord, vous utilisez le modèle ViewHolder incorrect. Le point du modèle ViewHolder est d'éviter d'appeler findViewById chaque fois que vous utilisez une vue recyclée. Lorsque converti est null, vous devez instancier une nouvelle vue, ce que vous faites. Le problème est que, dans ce cas, vous ne donnez aucune valeur à sa sous-vue ... vous retournez simplement la vue.

Un getView typique en utilisant le modèle ViewHolder ressemble à quelque chose comme ceci:

public View getView(int position, View convertView, 
    android.view.ViewGroup parent) { 
    View view = convertView; 
    ViewHolder viewHolder; 

    if(view == null) { 
    view = layoutInflater.inflate ... // instantiate new view here 

    // note that i'm instantiating my View holder when view == null, 
    // where you are instantiating it when view != null... 
    viewHolder = new ViewHolder(); 
    viewHolder.subview1 = (TextView)view.findViewById(R.id.subview1); 
    ... 
    viewHolder.subviewN = (CheckBox)view.findViewById(R.id.subviewN); 
    view.setTag(viewHolder); 
    } 

    viewHolder = (ViewHolder)view.getTag(); 

    // view and viewHolder are now appropriately set, so do with them what you must 

    viewHolder.subview1.setText("blah blah"); 
    ... 

    return view; 
} 

Comme je l'ai dit, vous assignez des valeurs à TextView, Button et CheckBox la vue que si convertView n'est pas nul ... En d'autres termes, lorsque vous créez une nouvelle vue, vous la renvoyez telle quelle. Peut-être que ce serait un bon endroit pour commencer le débogage.

Questions connexes