Provider的八种提供者

发布时间 2023-12-30 10:15:04作者: 鲤斌

代码

class Example extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Example"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            // 使用Consumer部件获取UserModel实例并订阅其变化
            Consumer<UserModel>(
              builder: (_, userModel, child) {
                // 在数据更新时,重新构建子部件,并显示userModel的name属性
                return Text(userModel.name,
                    style: const TextStyle(
                        color: Colors.red,
                        fontSize: 30
                    )
                );
              },
            ),
            // 使用Consumer部件获取UserModel实例并订阅其变化
            Consumer<UserModel>(
              builder: (_, userModel, child) {
                // 在数据更新时,重新构建子部件,并显示一个按钮,点击按钮会调用changeName方法改变name的值
                return Padding(
                  padding: const EdgeInsets.all(20),
                  child: ElevatedButton(
                    onPressed: (){
                      userModel.changeName();
                    },
                    child: const Text("改变值"),
                  ),
                );
              },
            ),
          ],
        ),
      ),
    );
  }
}

1、Provider:

通用的提供者,可用于共享任何对象,不仅仅是状态对象。在更新时,提供者会重新构建依赖于该对象的部件。

创建模型
//1 最基本的Provider组件,可以使用它为组件树中的任何位置提供值,
//组件但是当该值更改的时候,它并不会更新UI
class UserModel   extends ChangeNotifier {
  String name = "jimi";

  void changeName(){
    name = "hellp";
    print(name);
  }
}
应用程序入口设置
class MyApp9 extends StatelessWidget {
  const MyApp9({super.key});

  @override
  Widget build(BuildContext context) {
    return    Provider<UserModel>(
      create: (_) =>UserModel(),
      child:  MaterialApp(
        debugShowCheckedModeBanner: false,
        home: Example(),
      ),   
      );
  }
}

2、ChangeNotifierProvider:

用于将一个ChangeNotifier对象共享给其子孙节点,并监听状态变化。会监听模型对象的变化,而且当数据改变时,它也会重建Consumer(消费者)

创建模型
//2.ChangeNotifierProvider 它跟Provider组件不同,
//ChangeNotifierProvider会监听模型对象的变化,而且当数据改变时,
//它也会重建Consumer(消费者)
class UserModel with ChangeNotifier {

  String name = "Jimi";

  void changeName() {
    name = "hello";
    notifyListeners();
  }
}
应用程序入口设置
class MyApp9 extends StatelessWidget {
  const MyApp9({super.key});

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<UserModel>(
      create: (_) =>UserModel(),
      child:  MaterialApp(
        debugShowCheckedModeBanner: false,
        home: Example(),
      ),
      
      );
  }
}
 

3、FutureProvider:

用于共享Future对象,通常在异步操作和数据加载中使用。

  • FutureProvider只会重建一次
  • 默认显示初始值
  • 然后显示Future
  • 最后不会再次重建
创建模型
class UserModel {

  UserModel({required this.name});

  String name = "Jimi";

  Future<void> changeName() async {
    print(name);
    await Future.delayed(const Duration(milliseconds: 2000)); //模拟网络请求延迟两秒后改变其值
    name = "hello";
    print(name);
  }
}
class UserFuture {
  Future<UserModel> asyncGetUserModel2() async {
    await Future.delayed(const Duration(milliseconds: 6000));
    return UserModel(name: "获取新的数据");
  }
}
应用程序入口设置
class MyApp9 extends StatelessWidget {
  const MyApp9({super.key});

  @override
  Widget build(BuildContext context) {
    return    FutureProvider<UserModel>(
      create: (_) =>UserFuture().asyncGetUserModel2(),
      initialData: UserModel(name: "hello1"),  //必传 不传报错
      child:  MaterialApp(
        debugShowCheckedModeBanner: false,
        home: Example(),
      ),
      );
  }
}

4、StreamProvider:

用于共享流(Stream)对象,可以是Dart中的任何流。和FutureProvider一样,主要的区别在于值会根据多次触发重新构建UI。

创建模型
//4、StreamProvider提供流值,是围绕StreamBuilder,所提供的值会在传入的时候替换掉新值。
//和FutureProvider一样,主要的区别在于值会根据多次触发重新构建UI。
class UserModel {
 UserModel({required this.name});
  String name = "Jimi";

  void changeName() {
    name = "hello";
  }
}

//每隔一秒钟生成一个数字
class UserStream {

  Stream<UserModel> getStreamUserModel() {
    return Stream<UserModel>.periodic(const Duration(milliseconds: 1000),
        (value) => UserModel(name: "$value")
    ).take(10);
  }
}
应用程序入口设置
class MyApp9 extends StatelessWidget {
  const MyApp9({super.key});

  @override
  Widget build(BuildContext context) {
    return    StreamProvider<UserModel>(
      create: (_) => UserStream().getStreamUserModel(),
      initialData: UserModel(name: "hello1"),  //必传 不传报错
      child:  MaterialApp(
        debugShowCheckedModeBanner: false,
        home: Example(),
      ),
      );
  }
}

5、MultiProvider

在实际开发过程中肯定会有多个提供者,我们虽然可以采用嵌套的方式来解决,但是这样无疑是混乱的,

可读性级差。这个时候强大的MultiProvder就产生了

创建模型
class UserModel1 with ChangeNotifier {

  String name = "Jimi";

  void changeName() {
    name = "hello";
    notifyListeners();
  }
}

class UserModel4 with ChangeNotifier {

  String name = "Jimi";
  int age = 18;

  void changeName() {
    name = "hello";
    age = 20;
    notifyListeners();
  }
}
应用程序入口设置
return MultiProvider(
  providers: [
    ChangeNotifierProvider<UserModel1>(create: (_) => UserModel1()),
    ChangeNotifierProvider<UserModel4>(create: (_) => UserModel4()),
    /// 添加更多
  ],
  child: MaterialApp(
    debugShowCheckedModeBanner: false,
    home: MultiProviderExample(),
  ),
);
使用数据
class MultiProviderExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("MultiProviderExample"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Consumer<UserModel1>(
              builder: (_, userModel, child) {
                return Text(userModel.name,
                    style: TextStyle(
                        color: Colors.red,
                        fontSize: 30
                    )
                );
              },
            ),
            Consumer<UserModel4>(
              builder: (_, userModel, child) {
                return Text(userModel.age.toString(),
                    style: TextStyle(
                        color: Colors.green,
                        fontSize: 30
                    )
                );
              },
            ),
            Consumer2<UserModel1, UserModel4>(
              builder: (_, userModel1, userModel4, child) {
                return Padding(
                  padding: EdgeInsets.all(20),
                  child: ElevatedButton(
                    onPressed: (){
                      userModel1.changeName();
                      userModel4.changeName();
                    },
                    child: Text("改变值"),
                  ),
                );
              },
            ),
          ],
        ),
      ),
    );
  }
}

6、ProxyProvider:

用于根据其他提供者的值计算新值,并将新值共享给下游部件。

当我们有多个模型的时候,会有模型依赖另一个模型的情况,在这种情况下,

我们可以使用ProxyProvider从另一个提供者获取值,然后将其注入到另一个提供者中。

创建模型
class UserModel5 with ChangeNotifier {

  String name = "Jimi";

  void changeName({required String newName}) {
    name = newName;
    notifyListeners();
  }
}


class WalletModel {

  UserModel5? userModel5;

  WalletModel({this.userModel5});

  void changeName() {
    userModel5?.changeName(newName: "JIMI");
  }
}
应用程序入口设置
class MyApp9 extends StatelessWidget {
  const MyApp9({super.key});

  @override
  Widget build(BuildContext context) {
return MultiProvider(
  providers: [
    ChangeNotifierProvider<UserModel5>(create: (_) => UserModel5()),
    ProxyProvider<UserModel5, WalletModel>(
      update: (_, userModel5, walletModel) => WalletModel(userModel5: userModel5),
    )
  ],
  child: MaterialApp(
    debugShowCheckedModeBanner: false,
    home: ProxyProviderExample(),
  ),
);
  }
}
使用数据
class ProxyProviderExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("ProxyProviderExample"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Consumer<UserModel5>(
              builder: (_, userModel, child) {
                return Text(userModel.name,
                    style: const TextStyle(
                        color: Colors.red,
                        fontSize: 30
                    )
                );
              },
            ),
            Consumer<UserModel5>(
              builder: (_, userModel, child) {
                return Padding(
                  padding: EdgeInsets.all(20),
                  child: ElevatedButton(
                    onPressed: (){
                      userModel.changeName(newName: "hello");
                    },
                    child: Text("改变值"),
                  ),
                );
              },
            ),
            Consumer<WalletModel>(
              builder: (_, walletModel, child) {
                return Padding(
                  padding: EdgeInsets.all(20),
                  child: ElevatedButton(
                    onPressed: (){
                      walletModel.changeName();
                    },
                    child: Text("通过代理改变值"),
                  ),
                );
              },
            ),
          ],
        ),
      ),
    );
  }
}

7、ChangeNotifierProxyProvider

ProxyProvider原理一样,唯一的区别在于它构建和同步ChangeNotifierChangeNotifierProvider,当提供者数据变化时,将会重构UI。

创建模型

1.

class BookModel {
  
  static var _books = [
    Book(1, "夜的命名数"),
    Book(2, "大奉打更人"),
    Book(3, "星门"),
    Book(4, "大魏读书人"),
    Book(5, "我师兄实在太稳健了"),
    Book(6, "深空彼岸"),
  ];

  // 获取书籍长度
  int get length => _books.length;

  // 根据ID获取书籍
  Book getById(int id) => _books[id -1];

  // 根据索引获取数据
  Book getByPosition(int position) => _books[position];

  // 更多....
}

class Book {
  final int bookId;
  final String bookName;
  
  Book(this.bookId, this.bookName);
}

2.

class BookManagerModel with ChangeNotifier {

  // 依赖bookModel
  final BookModel _bookModel;

  // 获取数据所有的ID
  List<int>? _bookIds;

  // 构造函数
  BookManagerModel(this._bookModel, {BookManagerModel? bookManagerModel})
    : _bookIds = bookManagerModel?._bookIds ?? [];

  // 获取所有的书
  List<Book> get books => _bookIds!.map((id) => _bookModel.getById(id)).toList();

  // 根据索引获取数据
  Book getByPosition(int position) => books[position];

  // 获取书籍的长度
  int get length => _bookIds?.length ?? 0;

  // 添加书籍
  void addFaves(Book book) {
    _bookIds!.add(book.bookId);
    notifyListeners();
  }

  // 删除书籍
  void removeFaves(Book book) {
    _bookIds!.remove(book.bookId);
    notifyListeners();
  }
}
复制代码
应用程序入口设置
return MultiProvider(
  providers: [
    Provider(create: (_) => BookModel()),
    ChangeNotifierProxyProvider<BookModel, BookManagerModel>(
      create: (_) => BookManagerModel(BookModel()),
      update: (_, bookModel, bookManagerModel) => BookManagerModel(bookModel),
    )
  ],
  child: MaterialApp(
    debugShowCheckedModeBanner: false,
    home: ChangeNotifierProxyProviderExample(),
  ),
);
使用数据

1.

class ChangeNotifierProxyProviderExample extends StatefulWidget {
  @override
  _ChangeNotifierProxyProviderExampleState createState() => _ChangeNotifierProxyProviderExampleState();
}

class _ChangeNotifierProxyProviderExampleState extends State<ChangeNotifierProxyProviderExample> {


  var _selectedIndex = 0;
  var _pages = [PageA(), PageB()];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _pages[_selectedIndex],
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _selectedIndex,
        onTap: (index) {
          setState(() {
            _selectedIndex = index;
          });
        },
        items: [
          BottomNavigationBarItem(
            icon: Icon(Icons.book),
            label: "书籍列表"
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.favorite),
            label: "收藏"
          )
        ],
      ),
    );
  }
}

2.

class PageA extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    
    var bookModel = Provider.of<BookModel>(context);
    
    return Scaffold(
      appBar: AppBar(
        title: Text("书籍列表"),
      ),
      body: ListView.builder(
        itemCount: bookModel.length,
        itemBuilder: (_, index) => BookItem(id: index + 1),
      ),
    );
  }
}

3.

class PageB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    var bookManagerModel = Provider.of<BookManagerModel>(context);
    var bookCount = bookManagerModel.length;

    return Scaffold(
      appBar: AppBar(
        title: Text("收藏列表"),
      ),
      body: ListView.builder(
        itemCount: bookCount,
        itemBuilder: (_, index) => BookItem(id: bookManagerModel.getByPosition(index).bookId),
      ),
    );
  }
}

4.

class BookButton extends StatelessWidget {
  
  final Book book;
  
  BookButton({
    Key? key,
    required this.book
  }) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    
    var bookManagerModel = Provider.of<BookManagerModel>(context);
    
    return GestureDetector(
      onTap: bookManagerModel.books.contains(this.book)
          ?  () => bookManagerModel.removeFaves(this.book)
          :  () => bookManagerModel.addFaves(this.book),
      child: SizedBox(
        width: 100,
        height: 60,
        child: bookManagerModel.books.contains(this.book)
            ?  Icon(Icons.star, color: Colors.red,)
            :  Icon(Icons.star_border),
      ),
    );
  }
}

5.

class BookItem extends StatelessWidget {

  final int id;

  BookItem({
    Key? key,
    required this.id
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {

    var bookModel = Provider.of<BookModel>(context);
    var book = bookModel.getById(id);

    return ListTile(
      leading: CircleAvatar(
        child: Text("${book.bookId}"),
      ),
      title: Text("${book.bookName}",
        style: TextStyle(
            color: Colors.black87
        ),
      ),
      trailing: BookButton(book: book),
    );
  }
}

ListenableProxyProvider:

ListenableProxyProviderListenableProvider的一个变体,但是在使用上和ChangeNotifierProvider效果惊人的一致

 

此参考于Flutter Provider状态管理---八种提供者使用分析-腾讯云开发者社区-腾讯云 (tencent.com)