从 onClickListener 中自定义适配器创建的 ListView 中删除行
Delete row from ListView created by Custom Adapter in onClickListener
您好,我从服务器获取数据并将它们传递到我的自定义适配器中以填充我的 ListView。下面是我的自定义适配器代码:
public class AppointmentAdapter extends BaseAdapter {
private AppointmentAdapter adapter;
private Activity activity;
private ArrayList<HashMap<String, String>> data;
private static LayoutInflater inflater=null;
HashMap<String, String> todo = new HashMap<String, String>();
// String confirmation;
RelativeLayout confirm_corner;
public AppointmentAdapter(Activity a, ArrayList<HashMap<String, String>> d) {
activity = a;
data=d;
inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//imageLoader=new ImageLoader(activity.getApplicationContext());
}
public int getCount() {
return data.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(final int position, View convertView, ViewGroup parent) {
//View vi=convertView;
//if(convertView==null)
final View vi = inflater.inflate(R.layout.appointments_list_item, null);
adapter = new AppointmentAdapter(activity,data);
TextView aid = (TextView)vi.findViewById(R.id.aid); // id
TextView apptitle = (TextView)vi.findViewById(R.id.apptitle); // title
TextView starts_date = (TextView)vi.findViewById(R.id.starts_date); // created_at
TextView starts_time = (TextView)vi.findViewById(R.id.starts_time);
TextView contact = (TextView)vi.findViewById(R.id.contact);
TextView confirmation = (TextView)vi.findViewById(R.id.confirmation);
confirm_corner = (RelativeLayout)vi.findViewById(R.id.confirm_corner);
//CheckBox check = (CheckBox)vi.findViewById(R.id.tododone); // checkbox
todo = data.get(position);
// Setting all values in listview
aid.setText(todo.get(AppointmentsFragment.TAG_AID));
apptitle.setText(todo.get(AppointmentsFragment.TAG_APPTITLE));
starts_date.setText(todo.get(AppointmentsFragment.TAG_STARTDATE));
starts_time.setText(todo.get(AppointmentsFragment.TAG_STARTTIME));
contact.setText(todo.get(AppointmentsFragment.TAG_CONTACT));
confirmation.setText(todo.get(AppointmentsFragment.TAG_CONFIRMATION));
String test = todo.get(AppointmentsFragment.TAG_USER_EMAIL);
//Handle buttons and add onClickListeners
ImageView accept = (ImageView)vi.findViewById(R.id.accept);
ImageView deny = (ImageView)vi.findViewById(R.id.deny);
//String test = confirmation.getText().toString();
//&& (!test.equals(MainActivity.user_email))
Log.d("CONFIRMATION: ", MainActivity.user_email);
if (confirmation.getText().toString().equals("pending") ){
Log.d("PASS CONFIRMATION: ", confirmation.getText().toString());
confirm_corner.setVisibility(View.VISIBLE);
}
accept.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
//do something
confirm_corner = (RelativeLayout)vi.findViewById(R.id.confirm_corner);
Log.d("Button accept: ", MainActivity.user_email);
new Confirm_appointment().execute();
//vi.setBackgroundColor(Color.RED);
confirm_corner.setVisibility(View.GONE);
}
});
deny.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
//do something
Log.d("Button deny: ", MainActivity.user_email);
new Deny_appointment().execute();
confirm_corner.setVisibility(View.INVISIBLE);
//adapter = new AppointmentAdapter(this,data);
data.remove(position);
data.clear();
data.addAll(data);
adapter.notifyDataSetChanged();
}
});
return vi;
}
我希望在单击拒绝按钮时删除该行。我应该在我的代码中更改什么才能修复此问题?
下面两个调用的目的是什么?:
data.clear();
data.addAll(data);
要从 ListView
中删除元素,只需调用 data.remove(position)
,然后更新 Adapter
(adapter.notifyDataSetChanged()
)。看看是否有效。
不要在 AppointmentAdapter
中创建新的 AppointmentAdapter
。当您在删除一行后尝试 notifyDataSetChanged()
时,您会通知错误的适配器。您通知新构造的适配器,该适配器不是已更改数据的适配器。 (新建的那些也没有附加到列表视图,所以他们无法确保通知到达那个。)
您应该记住,只需要一个适配器即可与具有多个项目视图的 ListView 一起工作。您为每个项目视图构造一个适配器,但这不会起作用。适配器应该与 ListView 合作,而不是与项目视图合作。
我对您的代码做的很多事情都不同,我认为您应该实施 View Holder 模式。你可以阅读它 here。
更新
您必须在 this
上调用它,而不是调用 adapter.notifyDataSetChanged()
。其中 this
应该是您刚刚删除该行的适配器。因为您正在为 View.OnClickListener
使用匿名(非静态)内部 classes,所以您可以使用 AppointmentAdapter.this
到达外部 class,这是您想要的适配器。
试试这个:
deny.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
//do something
Log.d("Button deny: ", MainActivity.user_email);
new Deny_appointment().execute();
confirm_corner.setVisibility(View.INVISIBLE);
AppointmentAdapter.this.data.remove(position);
AppointmentAdapter.this.notifyDataSetChanged();
}
});
顺便说一句,我同意 Willis 的观点,即您清除数据并重新加载数据的行似乎是错误的。所以我也把它们扔掉了。
您好,我从服务器获取数据并将它们传递到我的自定义适配器中以填充我的 ListView。下面是我的自定义适配器代码:
public class AppointmentAdapter extends BaseAdapter {
private AppointmentAdapter adapter;
private Activity activity;
private ArrayList<HashMap<String, String>> data;
private static LayoutInflater inflater=null;
HashMap<String, String> todo = new HashMap<String, String>();
// String confirmation;
RelativeLayout confirm_corner;
public AppointmentAdapter(Activity a, ArrayList<HashMap<String, String>> d) {
activity = a;
data=d;
inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//imageLoader=new ImageLoader(activity.getApplicationContext());
}
public int getCount() {
return data.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(final int position, View convertView, ViewGroup parent) {
//View vi=convertView;
//if(convertView==null)
final View vi = inflater.inflate(R.layout.appointments_list_item, null);
adapter = new AppointmentAdapter(activity,data);
TextView aid = (TextView)vi.findViewById(R.id.aid); // id
TextView apptitle = (TextView)vi.findViewById(R.id.apptitle); // title
TextView starts_date = (TextView)vi.findViewById(R.id.starts_date); // created_at
TextView starts_time = (TextView)vi.findViewById(R.id.starts_time);
TextView contact = (TextView)vi.findViewById(R.id.contact);
TextView confirmation = (TextView)vi.findViewById(R.id.confirmation);
confirm_corner = (RelativeLayout)vi.findViewById(R.id.confirm_corner);
//CheckBox check = (CheckBox)vi.findViewById(R.id.tododone); // checkbox
todo = data.get(position);
// Setting all values in listview
aid.setText(todo.get(AppointmentsFragment.TAG_AID));
apptitle.setText(todo.get(AppointmentsFragment.TAG_APPTITLE));
starts_date.setText(todo.get(AppointmentsFragment.TAG_STARTDATE));
starts_time.setText(todo.get(AppointmentsFragment.TAG_STARTTIME));
contact.setText(todo.get(AppointmentsFragment.TAG_CONTACT));
confirmation.setText(todo.get(AppointmentsFragment.TAG_CONFIRMATION));
String test = todo.get(AppointmentsFragment.TAG_USER_EMAIL);
//Handle buttons and add onClickListeners
ImageView accept = (ImageView)vi.findViewById(R.id.accept);
ImageView deny = (ImageView)vi.findViewById(R.id.deny);
//String test = confirmation.getText().toString();
//&& (!test.equals(MainActivity.user_email))
Log.d("CONFIRMATION: ", MainActivity.user_email);
if (confirmation.getText().toString().equals("pending") ){
Log.d("PASS CONFIRMATION: ", confirmation.getText().toString());
confirm_corner.setVisibility(View.VISIBLE);
}
accept.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
//do something
confirm_corner = (RelativeLayout)vi.findViewById(R.id.confirm_corner);
Log.d("Button accept: ", MainActivity.user_email);
new Confirm_appointment().execute();
//vi.setBackgroundColor(Color.RED);
confirm_corner.setVisibility(View.GONE);
}
});
deny.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
//do something
Log.d("Button deny: ", MainActivity.user_email);
new Deny_appointment().execute();
confirm_corner.setVisibility(View.INVISIBLE);
//adapter = new AppointmentAdapter(this,data);
data.remove(position);
data.clear();
data.addAll(data);
adapter.notifyDataSetChanged();
}
});
return vi;
}
我希望在单击拒绝按钮时删除该行。我应该在我的代码中更改什么才能修复此问题?
下面两个调用的目的是什么?:
data.clear();
data.addAll(data);
要从 ListView
中删除元素,只需调用 data.remove(position)
,然后更新 Adapter
(adapter.notifyDataSetChanged()
)。看看是否有效。
不要在 AppointmentAdapter
中创建新的 AppointmentAdapter
。当您在删除一行后尝试 notifyDataSetChanged()
时,您会通知错误的适配器。您通知新构造的适配器,该适配器不是已更改数据的适配器。 (新建的那些也没有附加到列表视图,所以他们无法确保通知到达那个。)
您应该记住,只需要一个适配器即可与具有多个项目视图的 ListView 一起工作。您为每个项目视图构造一个适配器,但这不会起作用。适配器应该与 ListView 合作,而不是与项目视图合作。
我对您的代码做的很多事情都不同,我认为您应该实施 View Holder 模式。你可以阅读它 here。
更新
您必须在 this
上调用它,而不是调用 adapter.notifyDataSetChanged()
。其中 this
应该是您刚刚删除该行的适配器。因为您正在为 View.OnClickListener
使用匿名(非静态)内部 classes,所以您可以使用 AppointmentAdapter.this
到达外部 class,这是您想要的适配器。
试试这个:
deny.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
//do something
Log.d("Button deny: ", MainActivity.user_email);
new Deny_appointment().execute();
confirm_corner.setVisibility(View.INVISIBLE);
AppointmentAdapter.this.data.remove(position);
AppointmentAdapter.this.notifyDataSetChanged();
}
});
顺便说一句,我同意 Willis 的观点,即您清除数据并重新加载数据的行似乎是错误的。所以我也把它们扔掉了。