You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ListView项内Sell按钮点击更新SQLite数据库异常问题求助

解决库存应用Sell按钮的点击无响应与崩溃问题

你的问题主要来自两个关键错误,咱们一步步拆解修复:

核心问题分析

  1. 手动创建Activity实例完全无效:你在点击监听器里new CatalogActivity(),但Android的Activity必须由系统初始化管理,手动new出来的实例没有完整的生命周期,getContentResolver()根本无法正常工作,这就是第一次点击没反应的原因。
  2. 点击时访问已失效的Cursor:当你点击按钮时,原有的Cursor可能已经因为数据更新(比如ContentProvider的notifyChange)被关闭或替换,这时候再调用mCursor.getString()就会触发StaleDataException,导致第二次点击崩溃。

分步解决方案

1. 修复Activity实例获取方式,禁止手动new Activity

不要自己创建Activity实例,直接从按钮的上下文获取当前的CatalogActivity实例(因为Adapter是在Activity中初始化的,按钮的上下文就是Activity)。

2. 提前存储数据到按钮Tag,避免点击时访问Cursor

在bindView绑定数据的时候,就把当前商品的ID和数量存到按钮的Tag中,点击时直接从Tag取数据,彻底避开访问可能失效的Cursor:

修改后的bindView代码:

@Override
public void bindView(View view, Context context, Cursor cursor) {
    // ... 其他绑定逻辑(比如商品名称、价格等)
    
    Button sellButton = view.findViewById(R.id.sell_button);
    
    // 从Cursor中获取当前项的ID和数量,此时Cursor是有效的
    int itemId = cursor.getInt(cursor.getColumnIndex(InventoryContract.ItemEntry._ID));
    int currentQuantity = cursor.getInt(cursor.getColumnIndex(InventoryContract.ItemEntry.COLUMN_QUANTITY));
    
    // 用Pair存储这两个值,也可以自定义一个简单的ItemData类
    Pair<Integer, Integer> itemInfo = new Pair<>(itemId, currentQuantity);
    sellButton.setTag(itemInfo);
    
    sellButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // 从Tag中取出提前存储的数据
            Pair<Integer, Integer> info = (Pair<Integer, Integer>) v.getTag();
            int id = info.first;
            int quantity = info.second;
            
            // 获取正确的Activity实例
            CatalogActivity activity = (CatalogActivity) v.getContext();
            // 调用Activity的方法
            activity.decreaseCount(id, quantity);
        }
    });
}

3. 优化Activity中的decreaseCount方法

既然方法就在Activity里,完全不需要传入Context,直接用自身的getContentResolver(),还可以加个数量判断避免负数:

public void decreaseCount(int columnId, int quantity){
    // 防止数量变成负数
    if (quantity <= 0) {
        Toast.makeText(this, "商品数量不能小于0", Toast.LENGTH_SHORT).show();
        return;
    }
    
    int newQuantity = quantity - 1;
    ContentValues values = new ContentValues();
    values.put(InventoryContract.ItemEntry.COLUMN_QUANTITY, newQuantity);
    
    Uri updateUri = ContentUris.withAppendedId(InventoryContract.ItemEntry.CONTENT_URI, columnId);
    getContentResolver().update(updateUri, values,null, null);
}

4. 确保数据自动刷新

你的ContentProvider已经正确调用了getContext().getContentResolver().notifyChange(uri, null),所以如果主Activity使用了CursorLoader,它会自动监听数据变化并重新查询,ListView会自动更新显示最新数量。


为什么这样能解决问题?

  • 不再手动创建Activity,用系统托管的实例调用方法,确保ContentResolver能正常执行数据库更新,第一次点击就能生效。
  • 提前把数据存在按钮Tag里,点击时完全不依赖Cursor,避免了Cursor失效导致的崩溃问题。

内容的提问来源于stack exchange,提问作者paxcow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:49:37