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

Riverpod结合SQFlite使用后返回页面数据为空问题排查

问题分析与解决方案

你的问题核心在于Riverpod状态未正确持久化,以及异步状态管理的不当处理。以下是具体问题点和修复方案:


1. 核心问题点

1.1 Coffee类未实现相等性判断

你的addCoffee和removeCoffee方法依赖于contains和!=判断,但Coffee类未重写==运算符和hashCode,导致对象相等性判断失效。即使两个Coffee对象数据完全一致,也会被视为不同对象,引发状态更新异常。

1.2 异步初始化时机问题

当前仅在CartScreen的initState中调用loadCoffee,若其他页面先于CartScreen访问cartProvider,会获取初始空列表;且若状态未正确持久化,返回其他页面时可能丢失已加载的数据。

1.3 removeCoffee方法签名错误

该方法为异步操作但返回void,无法让调用者等待操作完成,可能导致状态更新与UI不同步。


2. 修复方案

2.1 完善Coffee类的相等性判断

修改Coffee模型类,重写==和hashCode:

class Coffee {
  final String id;
  final String coffeeImage;
  final String coffeeName;
  final double coffeePrice;

  Coffee({
    required this.id,
    required this.coffeeImage,
    required this.coffeeName,
    required this.coffeePrice,
  });

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is Coffee &&
          runtimeType == other.runtimeType &&
          id == other.id &&
          coffeeImage == other.coffeeImage &&
          coffeeName == other.coffeeName &&
          coffeePrice == other.coffeePrice;

  @override
  int get hashCode =>
      id.hashCode ^
      coffeeImage.hashCode ^
      coffeeName.hashCode ^
      coffeePrice.hashCode;
}

2.2 修复removeCoffee方法签名

将返回类型改为Future<void>:

Future<void> removeCoffee(Coffee coffee) async {
  final db = await _getDatabase();
  await db.delete(
    'cart_provider',
    where: 'id = ?',
    whereArgs: [coffee.id],
  );

  coffees = coffees.where((c) => c != coffee).toList();
  notifyListeners();
}

2.3 优化状态初始化方式(推荐使用AsyncNotifier)

Riverpod 2.0+的AsyncNotifier更适合处理异步状态,可自动管理加载、错误、数据三种状态,避免手动处理FutureBuilder的冗余代码:

修改CartNotifier为AsyncNotifier

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:path/path.dart' as path;
import 'package:sqflite/sqflite.dart' as sql;
import 'package:sqflite/sqlite_api.dart';

import 'package:coffee_shop_app/models/coffee.dart';

Future<Database> _getDatabase() async {
  final dbPath = await sql.getDatabasesPath();
  final db = await sql.openDatabase(
    path.join(dbPath, 'coffee.db'),
    onCreate: (db, version) {
      return db.execute(
          'CREATE TABLE cart_provider(id TEXT PRIMARY KEY, coffeeImage TEXT, CoffeeName TEXT, CoffeePrice REAL)');
    },
    version: 1,
  );
  return db;
}

class CartNotifier extends AsyncNotifier<List<Coffee>> {
  Future<List<Coffee>> _loadCoffee() async {
    final db = await _getDatabase();
    final data = await db.query('cart_provider');
    return data.map((row) => Coffee(
          id: row['id'] as String,
          coffeeImage: row['coffeeImage'] as String,
          coffeeName: row['CoffeeName'] as String,
          coffeePrice: row['CoffeePrice'] as double,
        )).toList();
  }

  @override
  Future<List<Coffee>> build() async {
    // 初始化时自动加载数据库数据
    return _loadCoffee();
  }

  Future<void> addCoffee(Coffee coffee) async {
    final currentState = state.valueOrNull ?? [];
    if (currentState.contains(coffee)) return;

    final db = await _getDatabase();
    await db.insert(
      'cart_provider',
      {
        'id': coffee.id,
        'coffeeImage': coffee.coffeeImage,
        'CoffeeName': coffee.coffeeName,
        'CoffeePrice': coffee.coffeePrice,
      },
    );

    state = AsyncData([...currentState, coffee]);
  }

  Future<void> removeCoffee(Coffee coffee) async {
    final currentState = state.valueOrNull ?? [];

    final db = await _getDatabase();
    await db.delete(
      'cart_provider',
      where: 'id = ?',
      whereArgs: [coffee.id],
    );

    state = AsyncData(currentState.where((c) => c != coffee).toList());
  }
}

final cartProvider = AsyncNotifierProvider<CartNotifier, List<Coffee>>(() {
  return CartNotifier();
});

修改CartScreen使用AsyncNotifier状态

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import 'package:coffee_shop_app/provider/cart_provider.dart';
import 'package:coffee_shop_app/components/registered_coffee_item.dart';

class CartScreen extends ConsumerWidget {
  const CartScreen({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final cartState = ref.watch(cartProvider);

    return cartState.when(
      loading: () => const Center(child: CircularProgressIndicator()),
      error: (error, stack) => Center(child: Text('加载出错: $error')),
      data: (registeredCoffees) {
        if (registeredCoffees.isEmpty) {
          return const Center(
            child: Text(
              '购物车是空的,去添加一些咖啡吧!',
              style: TextStyle(fontSize: 18),
            ),
          );
        }

        return Column(
          children: [
            Expanded(
              child: Padding(
                padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20),
                child: ListView(
                  children: registeredCoffees
                      .map((coffee) => RegisteredCoffeeItem(
                            coffee: coffee,
                            icon: Icons.delete,
                          ))
                      .toList(),
                ),
              ),
            ),
          ],
        );
      },
    );
  }
}

3. 其他页面状态监听

其他页面只需通过ref.watch(cartProvider)即可获取最新的购物车数据,无需额外处理加载逻辑:

// 示例:在首页监听购物车数量
final cartState = ref.watch(cartProvider);
cartState.when(
  loading: () => const Text('加载中...'),
  error: (_, __) => const Text('出错了'),
  data: (coffees) => Text('购物车: ${coffees.length}'),
);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 04:24:54