Menu
CoddyTech

多个模型:MultiProvider

本课属于 Coddy Flutter 学习旅程的“状态管理”单元。第 15 课,共 27 课。

让每个模型只负责一件事:一个类负责分数,另一个类负责生命值。小模型易于阅读,组件也只需监听自己需要的内容。包含多个模型的应用需要多个 Provider。

你可以将它们嵌套起来,让一个 Provider 成为下一个 Provider 的子级,但每增加一个模型,代码就会向右缩进。MultiProvider 接收一个扁平列表:

runApp(
  MultiProvider(
    providers: [
      ChangeNotifierProvider(create: (context) => Score()),
      ChangeNotifierProvider(create: (context) => Lives()),
    ],
    child: const MyApp(),
  ),
);

列表中的 Provider 都没有自己的 child:MultiProvider 会为你将它们叠加起来,并把 child 放在它们的下方。下面的每个组件都可以按模型的类型监听或读取任意模型,例如:context.watch<Lives>()。

challenge icon

挑战

简单

游戏页面会监听两个模型 Score 和 Lives,但 main 只提供了分数模型,因此应用会显示错误。

  • 将 main 中的 provider 替换为 MultiProvider,以提供这两个模型。

亲手试试

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class Score extends ChangeNotifier {
  int _points = 0;

  int get points => _points;

  void hit() {
    _points += 10;
    notifyListeners();
  }
}

class Lives extends ChangeNotifier {
  int _left = 3;

  int get left => _left;

  void miss() {
    if (_left > 0) {
      _left--;
      notifyListeners();
    }
  }
}

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => Score(),
      child: const MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: GamePage(),
    );
  }
}

class GamePage extends StatelessWidget {
  const GamePage({super.key});

  @override
  Widget build(BuildContext context) {
    final points = context.watch<Score>().points;
    final lives = context.watch<Lives>().left;
    return Scaffold(
      appBar: AppBar(title: Text('Lives: $lives')),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Text('Points: $points', style: const TextStyle(fontSize: 40)),
            const SizedBox(height: 16),
            Row(
              mainAxisSize: MainAxisSize.min,
              children: [
                ElevatedButton(
                  onPressed: () => context.read<Score>().hit(),
                  child: const Text('Hit'),
                ),
                const SizedBox(width: 16),
                ElevatedButton(
                  onPressed: () => context.read<Lives>().miss(),
                  child: const Text('Miss'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

状态管理中的所有课

自己练习: Flutter 在线编译器