Android AsyncTask 与 ListView 包含 Button onClickListener
我有一个列表视图,其中填充了 sqlitedatabase 中的数据。列表视图元素包含一个 TextView、一个按钮和一个复选框。单击该按钮将显示一个时间选择器对话框。从 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 对话框在 Activity 中创建的位置。
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 中获取所需的对象。当我将新的 Bundle 从适配器传输到活动时,此 Bunlde 是最终的并且永远不会改变。当我单击另一个按钮时,会显示相同的对话框(具有相同的值),并且 OnTimeSetListener 会与最终的捆绑包一起执行。有没有办法处理对话框表单适配器?我应该为 ViewHolder 中的每一行创建一个对话框吗?
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.
Now when I click on the seventh List-Item, the first list item is updated. There might be an error with the threads.
the activity:
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;
};
}
Thanks for your help - I changed the getView Method and started debugging everything.
I think the problem is where the TimePicker Dialog is created in the Activity.
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;
}
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
听起来 SettingsAdapter 类中的 getView 方法有问题。首先,您错误地使用了 ViewHolder 模式。 ViewHolder 模式的要点是避免每次使用回收视图时调用 findViewById。
当convertView为null时,您需要实例化一个新视图,这就是您正在做的事情。问题是,在这种情况下,您没有赋予其子视图任何值......您只是返回视图。
使用 ViewHolder 模式的典型 getView 看起来像这样:
正如我之前所说,只有在 ConvertView 不为 null 时,才为视图的 TextView、Button 和 CheckBox 赋值...换句话说,当您创建一个新 View 时,您只需按原样返回即可。也许这将是开始调试的好地方。
Sounds like something is wrong with your getView method in the SettingsAdapter class. First of all, you're using the ViewHolder pattern wrong. The point of the ViewHolder pattern is to avoid calling findViewById every time you used a recycled view.
When convertView is null, you need to instantiate a new view, which is what you're doing. The problem is that, in this case, you aren't giving its subview's any value... you are simply returning the view.
A typical getView using the ViewHolder pattern looks something like this:
As I said before, you are assigning values to the view's TextView, Button, and CheckBox only if convertView is not null... in other words, when you create a new View, you just return it as is. Maybe that would be a good place to start debugging.