如何在Flutter中使用Provider实现数据更新?技术求助
问题描述
使用Provider加载数据到页面,Provider类中存在带可选参数的getAllCharacters函数,初始数据可正常获取。在AppBar设置图标,点击后打开BottomSheet,希望点击BottomSheet内的按钮时传递参数调用该函数,用新数据更新现有数据,但多次尝试均未成功。
解决方案
1. 修改Provider类
添加加载状态管理,并在数据更新后通知UI刷新:
import 'package:flutter/material.dart'; import '../models/users.dart'; import '../repository/my_repository.dart'; class MyProvider extends ChangeNotifier{ MyProvider(this._myRepository); final MyRepository _myRepository; List<RickModel> _allRickCharacters = []; List<RickModel> get allRickCharacters => _allRickCharacters; // 新增加载状态,用于UI显示加载中提示 bool _isLoading = false; bool get isLoading => _isLoading; Future<void> getAllCharacters({String? species, String? gender, String? status }) async{ _isLoading = true; notifyListeners(); // 通知UI开始加载 try{ // 直接await获取数据,替代then写法更简洁 _allRickCharacters = await _myRepository.getAllCharacters( species: species, gender: gender, status: status ); }catch(e){ // 可添加错误处理逻辑,比如打印日志 print('数据加载失败:$e'); }finally{ _isLoading = false; notifyListeners(); // 通知UI数据更新完成 } } }
2. 修改HomeLayout组件
用Consumer监听Provider状态,替代FutureBuilder避免重复请求,同时重构BottomSheet为独立组件管理筛选参数:
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:rick_and_morty/pages/character_details.dart'; import 'package:rick_and_morty/pages/widgets/character_item.dart'; import '../models/users.dart'; import '../providers/my_provides.dart'; class HomeLayout extends StatefulWidget { const HomeLayout({Key? key}) : super(key: key); @override State<HomeLayout> createState() => _HomeLayoutState(); } class _HomeLayoutState extends State<HomeLayout> { @override void initState() { super.initState(); // 初始化加载数据,listen: false表示不监听状态变化 Provider.of<MyProvider>(context, listen: false).getAllCharacters(); } @ @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Center(child: Text('Users')), actions: [ IconButton( padding: const EdgeInsets.only(right: 25), onPressed: (){ showModalBottomSheet( context: context, builder: (context) => const FilterBottomSheet(), ); }, icon: const Icon(Icons.filter_list_sharp,size: 40,), ), ], ), body: Consumer<MyProvider>( builder: (context, provider, child){ // 初始加载或筛选时显示加载指示器 if(provider.isLoading && provider.allRickCharacters.isEmpty){ return const Center(child: CircularProgressIndicator()); } // 无数据时显示提示 if(provider.allRickCharacters.isEmpty){ return const Center(child: Text('暂无角色数据')); } // 数据加载完成,显示网格列表 return GridView.builder( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, childAspectRatio: 2 / 3, crossAxisSpacing: 1, mainAxisSpacing: 1, ), itemCount: provider.allRickCharacters.length, itemBuilder: (context,index) => CharacterItem( rickModel: provider.allRickCharacters[index], widget: CharacterDetails(rickModel: provider.allRickCharacters[index]), ) ); }, ), ); } } // 独立的筛选BottomSheet组件,管理筛选参数 class FilterBottomSheet extends StatefulWidget { const FilterBottomSheet({Key? key}) : super(key: key); @override State<FilterBottomSheet> createState() => _FilterBottomSheetState(); } class _FilterBottomSheetState extends State<FilterBottomSheet> { String? selectedSpecies; String? selectedGender; String? selectedStatus; @override Widget build(BuildContext context) { return Column( mainAxisSize: MainAxisSize.min, children: [ Container( alignment: Alignment.center, color: Colors.black, width: double.infinity, height: 50, child: const Text('筛选角色', style: TextStyle( color:Colors.white, fontSize: 22 ), ), ), Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('物种:'), Wrap( spacing: 8, children: ['Human', 'Alien', 'Robot'].map((species){ return ChoiceChip( label: Text(species), selected: selectedSpecies == species, onSelected: (selected){ setState(() { selectedSpecies = selected ? species : null; }); }, ); }).toList(), ), const SizedBox(height: 16), const Text('性别:'), Wrap( spacing: 8, children: ['Male', 'Female', 'Genderless'].map((gender){ return ChoiceChip( label: Text(gender), selected: selectedGender == gender, onSelected: (selected){ setState(() { selectedGender = selected ? gender : null; }); }, ); }).toList(), ), const SizedBox(height: 16), const Text('状态:'), Wrap( spacing: 8, children: ['Alive', 'Dead', 'Unknown'].map((status){ return ChoiceChip( label: Text(status), selected: selectedStatus == status, onSelected: (selected){ setState(() { selectedStatus = selected ? status : null; }); }, ); }).toList(), ), const SizedBox(height: 24), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('取消'), ), ElevatedButton( onPressed: (){ // 获取Provider实例,调用筛选函数 final provider = Provider.of<MyProvider>(context, listen: false); provider.getAllCharacters( species: selectedSpecies, gender: selectedGender, status: selectedStatus, ); Navigator.pop(context); }, child: const Text('应用筛选'), ), ], ) ], ), ), ], ); } }
关键修改说明
- Provider层:新增加载状态,数据更新后调用
notifyListeners()触发UI刷新,确保状态变更能被UI感知。 - UI层:用
Consumer替代FutureBuilder,避免组件重建时重复发起请求;在initState中初始化数据加载。 - BottomSheet:改为有状态组件维护筛选参数,点击"应用筛选"时获取Provider实例并传递参数调用接口,完成后关闭BottomSheet。
内容的提问来源于stack exchange,提问作者MhmD Yo
相关产品推荐
相关产品推荐

