ListView删除元素异常:删除最后一个而非目标元素
问题描述
我需要实现ListView的视图添加与删除功能:点击ADD按钮添加对象(视图),长按列表项弹出窗口执行删除操作。目前其他功能正常,但删除时总是移除ArrayList的最后一个元素,而非长按选中的目标元素。我知道可以通过标记对象或索引实现,但不清楚如何结合现有程序架构适配。
现有代码
MainActivity.java
public class MainActivity extends AppCompatActivity { // Construct the data source ArrayList<User> arrayOfUsers = new ArrayList<User>(); ListView listview; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Create the adapter to convert the array to views UsersAdapter adapter = new UsersAdapter(this, arrayOfUsers); // Attach the adapter to a ListView ListView listView = (ListView) findViewById(R.id.book_list); listView.setAdapter(adapter); Button add = (Button)findViewById(R.id.add); // Activates method on yes button click add.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View view){ arrayOfUsers.add(new User("test", "test")); adapter.notifyDataSetChanged(); } }); listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) { final int itemToDelete = i; // To delete the data from the App new AlertDialog.Builder(MainActivity.this) .setIcon(android.R.drawable.ic_dialog_alert) .setTitle("Are you sure?") .setMessage("Do you want to delete this note?") .setPositiveButton("Yes", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { arrayOfUsers.remove(itemToDelete); adapter.notifyDataSetChanged(); } }).setNegativeButton("No", null).show(); return true; } }); } }
UsersAdapter.java
public class UsersAdapter extends ArrayAdapter<User> { private ArrayList<User> users; public UsersAdapter(Context context, ArrayList<User> users) { super(context, 0, users); this.users = users; } @Override public View getView(int position, View convertView, ViewGroup parent) { // Get the data item for this position User user = getItem(position); // Check if an existing view is being reused, otherwise inflate the view if (convertView == null) { convertView = LayoutInflater.from(getContext()).inflate(R.layout.list_item, parent, false); } // Lookup view for data population TextView tvName = (TextView) convertView.findViewById(R.id.tvName); TextView tvHome = (TextView) convertView.findViewById(R.id.tvHome); // Populate the data into the template view using the data object tvName.setText(user.name); tvHome.setText(user.hometown); EditText input_weight = (EditText) convertView.findViewById(R.id.weight); Button save = (Button) convertView.findViewById(R.id.save); // Activates method on yes button click save.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View view){ SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getContext().getApplicationContext()); SharedPreferences.Editor editor = pref.edit(); String bw = String.valueOf(input_weight.getText()); editor.putString("input_weight", bw); editor.commit(); // Saves body weight bw = pref.getString("body_weight", bw); // Gets body weight tvHome.setText(bw); // Displays body weight } }); // Return the completed view to render on screen return convertView; } }
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <ListView android:id="@+id/book_list" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="0dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:listitem="@layout/list_item"/> <Button android:id="@+id/add" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="ADD" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="1.0" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
list_item.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity"> <TextView android:id="@+id/tvName" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Name" /> <EditText android:id="@+id/weight" android:layout_width="wrap_content" android:layout_height="wrap_content" android:ems="10" android:inputType="textPersonName" android:hint="Weight" /> <TextView android:id="@+id/tvHome" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="HomeTown" /> <Button android:id="@+id/save" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Save" android:focusable="false" /> </LinearLayout>
解决方案
1. 修复删除逻辑
直接通过Adapter的remove方法删除选中对象,避免索引关联错误:
listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) { final User targetUser = adapter.getItem(i); new AlertDialog.Builder(MainActivity.this) .setIcon(android.R.drawable.ic_dialog_alert) .setTitle("确定删除?") .setMessage("你确定要删除这条记录吗?") .setPositiveButton("是", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int which) { // Adapter的remove方法会自动更新数据源并刷新视图 adapter.remove(targetUser); } }).setNegativeButton("否", null).show(); return true; } });
2. 优化Adapter的视图复用与数据存储
使用ViewHolder模式避免重复绑定点击事件,同时修复SharedPreferences的key冲突问题:
public class UsersAdapter extends ArrayAdapter<User> { public UsersAdapter(Context context, ArrayList<User> users) { super(context, 0, users); } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if (convertView == null) { convertView = LayoutInflater.from(getContext()).inflate(R.layout.list_item, parent, false); holder = new ViewHolder(); holder.tvName = convertView.findViewById(R.id.tvName); holder.tvHome = convertView.findViewById(R.id.tvHome); holder.input_weight = convertView.findViewById(R.id.weight); holder.save = convertView.findViewById(R.id.save); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } final User user = getItem(position); holder.tvName.setText(user.name); holder.tvHome.setText(user.hometown); // 绑定当前用户和位置到按钮Tag holder.save.setTag(user); holder.save.setTag(R.id.tag_position, position); holder.save.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View view){ User currentUser = (User) view.getTag(); int pos = (int) view.getTag(R.id.tag_position); SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getContext()); SharedPreferences.Editor editor = pref.edit(); String bw = holder.input_weight.getText().toString().trim(); // 用位置作为key后缀,避免不同item的数据互相覆盖 editor.putString("weight_" + pos, bw); editor.apply(); bw = pref.getString("weight_" + pos, bw); holder.tvHome.setText(bw); // 更新数据源对象,保持数据一致性 currentUser.hometown = bw; } }); return convertView; } static class ViewHolder { TextView tvName; TextView tvHome; EditText input_weight; Button save; } }
3. 添加Tag ID定义
在res/values/ids.xml中添加位置Tag的ID(无该文件则新建):
<?xml version="1.0" encoding="utf-8"?> <resources> <item name="tag_position" type="id"/> </resources>
内容的提问来源于stack exchange,提问作者wickedesperatevirgin
相关产品推荐
相关产品推荐

