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

Flutter中ChangeNotifierProxyProvider更新时如何持久化子Provider状态?

问题:ChangeNotifierProxyProvider更新时丢失Job的career数据

现有Person和Job两个ChangeNotifier Provider,Job依赖Person。通过ChangeNotifierProxyProvider初始化后,在initState中设置Job的career为Accountant,初始可正常打印包含该值的title;但调用Person的increaseAge方法更新年龄后,Job的career恢复为默认值"na"。如何在Person更新时持久化Job的career数据?

相关代码

Person类

class Person with ChangeNotifier {
  Person({required this.name, required this.age});

  final String name;
  int age;

  void increaseAge() {
    age++;
    notifyListeners();
  }
}

Job类

class Job with ChangeNotifier {
  Job(this.person);

  String career = "na";

  addCareer(value) {
    career = value;
    notifyListeners();
  }

  final Person person;
  String get title {
    return '${person.name}, $career, ${person.age}';
  }
}

初始化代码

void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider<Person>(create: (_) => Person(name: 'John', age: 25)),
        ChangeNotifierProxyProvider<Person, Job>(
          create: (BuildContext context) => Job(Provider.of<Person>(context, listen: false)),
          update: (BuildContext context, Person person, Job? job) => Job(person),
        ),
      ],
      child: const MyApp(),
    ),
  );
}

initState代码

@override
void initState() {
  super.initState();

  final job = Provider.of<Job>(context, listen: false);
  job.addCareer("Accountant");
}

解决方案

问题根源在于ChangeNotifierProxyProvider的update方法每次都新建Job实例,新实例的career会重置为默认值"na",覆盖之前设置的值。要解决这个问题,需要复用已有的Job实例,仅更新其中依赖的Person引用,保留原有的career数据。

步骤1:修改Job类,支持更新Person引用

将Job类中final Person person改为可更新的私有变量,并添加更新方法:

class Job with ChangeNotifier {
  Job(this._person);

  String career = "na";
  Person _person;

  // 更新Person引用的方法
  void updatePerson(Person newPerson) {
    _person = newPerson;
    notifyListeners();
  }

  void addCareer(String value) {
    career = value;
    notifyListeners();
  }

  // 对外暴露person的 getter
  Person get person => _person;

  String get title {
    return '${_person.name}, $career, ${_person.age}';
  }
}

步骤2:修改ChangeNotifierProxyProvider的update逻辑

不再新建Job实例,而是复用现有实例并更新Person引用:

void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider<Person>(create: (_) => Person(name: 'John', age: 25)),
        ChangeNotifierProxyProvider<Person, Job>(
          create: (context) => Job(Provider.of<Person>(context, listen: false)),
          update: (context, person, job) {
            // 复用已有的Job实例,仅更新Person引用
            job?.updatePerson(person);
            // 首次创建时返回新实例,后续返回复用的实例
            return job ?? Job(person);
          },
        ),
      ],
      child: const MyApp(),
    ),
  );
}

原理说明

当Person更新并调用notifyListeners()时,ChangeNotifierProxyProvider会触发update方法。此时我们不再创建新的Job实例,而是对已有的Job实例仅更新其Person引用,保留之前通过addCareer设置的career值,从而实现数据持久化。

内容的提问来源于stack exchange,提问作者s-hunter

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 02:54:22