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

如何在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('应用筛选'),
                  ),
                ],
              )
            ],
          ),
        ),
      ],
    );
  }
}

关键修改说明

  1. Provider层:新增加载状态,数据更新后调用notifyListeners()触发UI刷新,确保状态变更能被UI感知。
  2. UI层:用Consumer替代FutureBuilder,避免组件重建时重复发起请求;在initState中初始化数据加载。
  3. BottomSheet:改为有状态组件维护筛选参数,点击"应用筛选"时获取Provider实例并传递参数调用接口,完成后关闭BottomSheet。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 13:05:41