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
相关产品推荐
相关产品推荐

