繁体   English   中英

带有ListView的Android AsyncTask包含Button onClickListener

[英]Android AsyncTask with ListView containing Button onClickListener

我有一个用数据表单sqlitedatabase填充的listview。 列表视图元素包含一个TextView,一个Button和一个Checkbox。 单击按钮将显示一个时间选择器对话框。 从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方法并开始调试所有内容。

我认为问题是在“活动”中创建“时间选择器”对话框的位置。

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

我从捆绑包中获取所需的对象。 当我将新的Bundle从适配器转移到Activity时,此Bunlde是最终的,永远不会更改。 当我单击另一个按钮时,将显示相同的对话框(具有相同的值),并使用该最终捆绑包执行OnTimeSetListener。 有没有办法处理Dialiogs表单适配器? 我应该为ViewHolder中的每一行创建一个对话框吗?

听起来好像SettingsAdapter类中的getView方法有问题。 首先,您使用的ViewHolder模式错误。 ViewHolder模式的要点是避免每次使用回收视图时都调用findViewById。

当convertView为null时,您需要实例化一个新视图,这就是您正在做的事情。 问题是,在这种情况下,您没有赋予其子视图任何值……您只是在返回视图。

使用ViewHolder模式的典型getView看起来像这样:

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

如前所述,仅当convertView不为null时,才为视图的TextView,Button和CheckBox分配值。换句话说,当您创建新的View时,只需按原样返回即可。 也许那将是开始调试的好地方。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM