Flutter使用Provider实现筛选功能时UI不更新问题求助
问题分析与修复方案
核心问题1:Provider未触发UI更新通知
你的CustomerProvider中getCustomer方法仅更新了_responseCustomer变量,但没有调用notifyListeners(),导致UI无法感知数据变化。
核心问题2:GridView使用了独立的Provider实例
在页面body部分,你给GridView包裹了一个新的ChangeNotifierProvider,这会创建一个全新的局部CustomerProvider实例,和页面上层获取的Provider不是同一个对象,数据完全隔离,自然不会同步更新。
修复步骤
1. 修正CustomerProvider的getCustomer方法
修改getCustomer,使用已定义的setter(setter中已包含notifyListeners())来自动触发UI更新:
class CustomerProvider with ChangeNotifier { ResponseCustomer? _responseCustomer; ResponseCustomer? get responseCustomer => _responseCustomer; set responseCustomer(ResponseCustomer? responseCustomer) { _responseCustomer = responseCustomer; notifyListeners(); } Future<ResponseCustomer> getCustomer({String? filter}) async { ResponseCustomer responseCustomer = await CustomerService().getCustomer(filter: filter); // 使用setter自动触发notifyListeners this.responseCustomer = responseCustomer; debugPrint(responseCustomer.data?.length.toString()); return responseCustomer; } }
2. 移除GridView外层的多余Provider
删除GridView所在的ChangeNotifierProvider,直接使用上层Consumer传递的customer实例:
class _CustomerPageState extends State<CustomerPage> { getCustomer({String? filter}) async { EasyLoading.show(status: 'Loading . . .'); await Provider.of<CustomerProvider>(context, listen: false) .getCustomer(filter: filter); EasyLoading.dismiss(); } @override Widget build(BuildContext context) { return Consumer<CustomerProvider>( builder: (context, customer, _) => Scaffold( backgroundColor: Colors.white, floatingActionButton: FloatingActionButton( onPressed: () { showModalBottomSheet( shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(30))), context: context, builder: (context) { return StatefulBuilder(builder: (context, setState) { return SizedBox( height: 200, width: MediaQuery.of(context).size.width, child: Padding( padding: const EdgeInsets.all(20.0), child: Column( children: [ const SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ TextButton( onPressed: () { getCustomer(filter: 'all'); Navigator.pop(context); }, style: TextButton.styleFrom( backgroundColor: primaryColor), child: Text('All', style: whiteTextStyle.copyWith( fontSize: 13, fontWeight: medium))), TextButton( onPressed: () { getCustomer(filter: 'suspect'); Navigator.pop(context); }, style: TextButton.styleFrom( backgroundColor: primaryColor), child: Text('Suspect', style: whiteTextStyle.copyWith( fontSize: 13, fontWeight: medium))), TextButton( onPressed: () { getCustomer(filter: 'low'); Navigator.pop(context); }, style: TextButton.styleFrom( backgroundColor: primaryColor), child: Text('Low', style: whiteTextStyle.copyWith( fontSize: 13, fontWeight: medium))), TextButton( onPressed: () { getCustomer(filter: 'medium'); Navigator.pop(context); }, style: TextButton.styleFrom( backgroundColor: primaryColor), child: Text('Medium', style: whiteTextStyle.copyWith( fontSize: 13, fontWeight: medium))) ], ), ], ), ), ); }); }, ); }, backgroundColor: primaryColor, child: Icon( Icons.filter_list_rounded, size: 30, color: accentColor, ), ), appBar: AppBar( automaticallyImplyLeading: false, elevation: 0, backgroundColor: primaryColor, title: RichText( text: TextSpan( text: 'Pelanggan ', style: whiteTextStyle.copyWith( fontSize: 25, fontWeight: bold), children: <TextSpan>[ TextSpan( text: '(${customer.responseCustomer?.data?.length})', style: whiteTextStyle.copyWith( fontSize: 15, fontWeight: bold)) ]), ), ), body: Padding( padding: const EdgeInsets.all(10.0), child: Column( children: [ SizedBox( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height - 166, // 移除此处的ChangeNotifierProvider child: GridView.builder( gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 200, childAspectRatio: 3 / 2, crossAxisSpacing: 3, mainAxisSpacing: 5), itemCount: customer.responseCustomer?.data?.length, itemBuilder: (context, index) { return Card( elevation: 4, color: secondaryColor, child: InkWell( splashColor: accentColor, onTap: () { debugPrint('index number $index tapped'); }, child: Padding( padding: const EdgeInsets.all(7.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.account_circle_rounded, size: 40, color: accentColor, ) ], ), Text( '${customer.responseCustomer?.data?[index].nmCustomer}', style: whiteTextStyle.copyWith( fontSize: 13, fontWeight: bold), ), Text( '+62 ${customer.responseCustomer?.data?[index].hpCustomer}', style: whiteTextStyle.copyWith( fontSize: 13, fontWeight: bold), ), ], ), ), ), ); }, ), ), ], ), ), )); } }
额外说明
- 确保
CustomerPage所在的Widget树上层已通过ChangeNotifierProvider注册CustomerProvider(比如MaterialApp外层),否则Provider.of和Consumer会找不到对应实例。 - 修复后,选择筛选条件调用
getCustomer时,Provider会更新数据并通知UI,Consumer会重新构建,AppBar计数和GridView内容都会同步更新。
内容的提问来源于stack exchange,提问作者Mifta Khussolikhin
相关产品推荐
相关产品推荐

