ExpandableListView子项删除按钮点击始终获取最后一条数据问题
问题根因
出现点击删除按钮永远获取到最后一个子项数据的问题,核心是变量作用域使用错误:
- 你把
txtBCN、txtmvpID、removeMVP甚至计数用的ctrVisit都定义成了Activity层面的全局变量。ExpandableListView和普通ListView一样通过View复用机制渲染列表项,每渲染一个子项就会执行一次getChildView方法,这些全局变量会被反复赋值为当前正在渲染的子项控件实例。等列表全部渲染完成,这些全局变量存的永远是最后一个子项的控件引用,不管你点击哪个位置的删除按钮,取到的都是最后一项的数据。 - 你的代码里还存在两个附带问题:一是
fillData方法中if和else分支的代码完全重复,属于无意义冗余;二是COA.equals(0)判断永远不会生效,因为COA是字符串类型,和整数0做equals比较永远返回false。
修复方案
核心修改逻辑是把所有和单个列表项绑定的控件、数据都改成方法内的局部变量,不要用全局变量存储单item的状态:
- 将子项控件声明全部移到
getChildView方法内部,作为局部变量存在 - 绑定子项View时,提前把当前项需要用到的分支名称、MVPID等数据存为final局部变量,点击事件触发时直接使用这些提前存好的值,不要等点击时再去全局控件里取
- 清理
fillData里的冗余代码,修正无效的条件判断
修复后的核心代码
优化后的fillData方法
private void fillData(){ int COA = dataBaseHelper.getCount(VisitDate); mGroupsCursor = dataBaseHelper.getSelectedParentMVPDate(reformatMVPDate()); startManagingCursor(mGroupsCursor); mGroupsCursor.moveToFirst(); ExpandableListView SelectedListView = (ExpandableListView) findViewById(R.id.MVPListitem); mAdapter = new MyExpandableListAdapter(mGroupsCursor, this, R.layout.mvp_list_parent, R.layout.mvp_list_child, new String[]{DataBaseHelper.MVP_INDUSTRY_TYPE}, new int[]{R.id.txtMVPParent}, new String[]{DataBaseHelper.MVP_BRCH_CODE_NAME, DataBaseHelper.MVP_BRCH_ADDRESS, DataBaseHelper.MVP_ID}, new int[]{R.id.txtviewBrnchCodeName, R.id.txtviewBrchAddr, R.id.txtmvpID}); SelectedListView.setAdapter(mAdapter); }
修复后的getChildView方法
@Override public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { View rowView = super.getChildView(groupPosition, childPosition, isLastChild, convertView, parent); // 所有子项控件声明为方法内局部变量,禁止使用全局变量存储单item控件 Button removeMVP = (Button) rowView.findViewById(R.id.btnRemove); TextView txtBCN = (TextView) rowView.findViewById(R.id.txtviewBrnchCodeName); TextView txtBA = (TextView) rowView.findViewById(R.id.txtviewBrchAddr); TextView txtmvpID = (TextView) rowView.findViewById(R.id.txtmvpID); // 提前将当前项需要用到的数据存为final局部变量,点击时直接取用 final String currentBranchName = txtBCN.getText().toString(); final String currentMvpId = txtmvpID.getText().toString(); if(edit.getVisibility() == View.VISIBLE){ removeMVP.setVisibility(View.GONE); } else { removeMVP.setVisibility(View.VISIBLE); } removeMVP.setOnClickListener(new View.OnClickListener() { @SuppressLint("Range") public void onClick(View v) { AlertDialog.Builder builder = new AlertDialog.Builder(MasterVisitPlan.this); builder.setTitle("Delete Appointment") .setMessage("Are you sure? Assigned date and branch will be removed." + currentBranchName) .setCancelable(false) .setPositiveButton("Yes", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Cursor res = dataBaseHelper.getCounterVisitData(currentBranchName, reformatDate()); // 计数变量也改为局部变量,避免全局变量值错乱 String ctrVisit = "0"; if(res.getCount() != 0){ while (res.moveToNext()){ ctrVisit = res.getString(3); } int diffCounterVisit = Integer.parseInt(ctrVisit) - 1; dataBaseHelper.updateCounterVisit(currentBranchName,String.valueOf(diffCounterVisit),reformatDate()); } Integer deletedRows = dataBaseHelper.DeleteSelectedChildMVPDate(currentMvpId); if(deletedRows > 0){ AlertDialog.Builder builder = new AlertDialog.Builder(MasterVisitPlan.this); builder.setMessage("✔ Successfully removed.") .setCancelable(false) .setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { edit.clearAnimation(); dialog.cancel(); setMonthView(); getStatus(); btnViewfromUploadStatus(); enableView(calendar, false); } }); AlertDialog dialogDeleted = builder.create(); dialogDeleted.show(); }else{ Toast.makeText(MasterVisitPlan.this, "Data not Deleted", Toast.LENGTH_SHORT).show(); } fillData(); countMVPData(); } }) .setNegativeButton("No", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } }); AlertDialog dialog = builder.create(); dialog.show(); } }); return rowView; }
额外提醒:
startManagingCursor方法从API 11开始已被废弃,后续维护建议替换为CursorLoader实现,避免Cursor生命周期管理不当引发内存泄漏。
内容的提问来源于stack exchange,提问作者Ryan Baltazar
相关产品推荐
相关产品推荐

