Android AsyncTask с ListView, содержащим кнопку onClickListener - PullRequest
1 голос
/ 22 октября 2011

У меня есть список, который заполнен формой данных sqlitedatabase. Элемент списка содержит TextView a Button и флажок. Нажатие на кнопку показывает диалог выбора времени. Принятие времени из timepickerdialog запускает AsyncTask. Когда я нажимаю кнопку, всегда создается новый AsyncTask.

Теперь, когда я нажимаю на седьмой элемент списка, первый элемент списка обновляется. Может быть ошибка с потоками.

активность:

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

Спасибо за вашу помощь - я изменил метод getView и начал отлаживать все.

Мне кажется, проблема в том, что в Упражнении создается диалог TimePicker.

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

Я получаю необходимый объект из комплекта. Этот Bunlde является окончательным и никогда не меняется, когда я переношу новый комплект из адаптера в действие. Когда я нажимаю на другую кнопку, появляется тот же диалог (с тем же значением), и OnTimeSetListener выполняется с этим последним пакетом. Есть ли способ обработки адаптеров формы Dialiogs? Должен ли я создать один диалог для каждой строки в ViewHolder?

1 Ответ

1 голос
/ 22 октября 2011

Похоже, что-то не так с вашим методом getView в классе SettingsAdapter.Прежде всего, вы используете шаблон ViewHolder неправильно.Смысл шаблона ViewHolder состоит в том, чтобы избегать вызова findViewById каждый раз, когда вы используете переработанное представление.

Когда convertView имеет значение null, вам нужно создать новое представление, что вы и делаете.Проблема в том, что в этом случае вы не присваиваете никакому значению его подпредставления ... вы просто возвращаете представление.

Типичный getView с использованием шаблона ViewHolder выглядит примерно так:

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

Как я уже говорил ранее, вы присваиваете значения TextView, Button и CheckBox в представлении только в том случае, если convertView не равно NULL ... другими словами, когда вы создаете новое представление, вы просто возвращаете его как есть.Может быть, это было бы хорошим местом для начала отладки.

...