如何利用selection和selectionArgs重构ContentProvider的update方法(MatrixCursor)
嘿,我来帮你搞定这个update方法的重构问题!你的核心需求是利用selection和selectionArgs定位要更新的条目,并且只修改传入的列、保留其他列的值,同时不依赖SQLite,基于内存列表来实现对吧?
核心思路拆解
- 匹配筛选条件:解析
selection和selectionArgs,从items列表中找到符合条件的条目 - 部分字段更新:只更新
ContentValues中存在的字段,未传入的字段保留原有值 - 统计更新行数:返回实际更新的条目数量,符合ContentProvider的规范
- 通知数据变化:更新完成后通知Resolver数据已变更
具体代码实现
首先,我们先写一个辅助方法来判断某个Item是否匹配传入的筛选条件:
private boolean doesItemMatchSelection(Item item, String selection, String[] selectionArgs) { // 没有筛选条件时,所有条目都匹配 if (TextUtils.isEmpty(selection)) { return true; } // 这里处理简单的单条件筛选(比如"user_id = ?"或"user_email = ?") // 如果需要支持AND/OR等复杂条件,可以扩展这个逻辑 String[] conditionParts = selection.split("="); if (conditionParts.length != 2) { return false; } String targetColumn = conditionParts[0].trim(); String expectedValue = selectionArgs != null && selectionArgs.length > 0 ? selectionArgs[0] : ""; switch (targetColumn) { case K.USER_ID_COLUMN_NAME: return item.userID.equals(expectedValue); case K.USER_EMAIL_COLUMN_NAME: return item.userEmail.equals(expectedValue); default: return false; } }
然后是重构后的update方法:
@Override public int update(@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) { int updatedCount = 0; // 如果列表为空,原逻辑是添加新数据,这里可以根据需求选择保留或移除 // 通常update操作不应新增数据,所以我注释掉了这部分,你可以按需调整 // if (items.isEmpty()) { // add(values); // updatedCount = 1; // } else { // 遍历所有条目,找到匹配筛选条件的进行更新 for (int i = 0; i < items.size(); i++) { Item currentItem = items.get(i); if (doesItemMatchSelection(currentItem, selection, selectionArgs)) { // 只更新传入的字段,未传入的保留原值 String newUserId = values.containsKey(K.USER_ID_COLUMN_NAME) ? values.getAsString(K.USER_ID_COLUMN_NAME) : currentItem.userID; String newUserEmail = values.containsKey(K.USER_EMAIL_COLUMN_NAME) ? values.getAsString(K.USER_EMAIL_COLUMN_NAME) : currentItem.userEmail; // 替换列表中的旧条目 items.set(i, new Item(newUserId, newUserEmail)); updatedCount++; } } // } // 有更新时才通知数据变化 if (updatedCount > 0) { getContext().getContentResolver().notifyChange(uri, null); } return updatedCount; }
优化建议(可选)
你的Item类目前是不可变的(没有setter方法),每次更新都要创建新对象。如果允许修改Item类,可以添加setter方法,这样能避免重复创建对象,提升效率:
private static class Item { String userID; String userEmail; Item(String userID, String userEmail) { this.userID = userID; this.userEmail = userEmail; } // 添加setter方法 public void setUserID(String userID) { this.userID = userID; } public void setUserEmail(String userEmail) { this.userEmail = userEmail; } }
对应的update逻辑可以改成:
if (values.containsKey(K.USER_ID_COLUMN_NAME)) { currentItem.setUserID(values.getAsString(K.USER_ID_COLUMN_NAME)); } if (values.containsKey(K.USER_EMAIL_COLUMN_NAME)) { currentItem.setUserEmail(values.getAsString(K.USER_EMAIL_COLUMN_NAME)); } // 因为是对象引用,修改内部字段后列表中的条目会自动更新,不需要调用items.set(i, currentItem) updatedCount++;
这样就完美实现了你要的功能:通过筛选条件定位条目,只更新指定列,保留其他列的值,完全基于内存列表操作,不需要SQLite。
内容的提问来源于stack exchange,提问作者waseefakhtar
相关产品推荐
相关产品推荐

