flutter provider create: (_) => xxxx(),

发布时间 2023-07-14 12:03:10作者: hztech

Provider通常使用ChangeNotifierProvider配合ChangeNotifier一起来实现状态的管理与Widget的更新。

ChangeNotifierProvider本质上其实就是Widget,它作为父节点Widget,可将数据共享给其所有子节点Widget使用或更新;

    • 创建model,继承ChangeNotifier,用来实现数据更新的通知并监听数据的变化

       
    •   调用notifyListeners()通知给监听方

       

    • 创建ChangeNotifierProvider,用来声明Provider,实现跨组建的数据共享;

    • 用ChangeNotifierProvider将父布局包裹,在父或子节点ChildA通过Provider.of<T>(BuildContext context, {bool listen = true})进行数据操作,
      可同步更新父与子的数据与UI。其中listen默认为true可监听数据的变化,为false的情况只可读取数据的值

       


  • 接收共享数据;context.watch<>()和context.read<>()

  • 不管是在父节点还是在子节点,都可以对ProviderViewModel的数据进行操作和监听。
    例1在操作与读取时使用的是Provider.of<T>(BuildContext context, {bool listen = true})的方式,
    为了可以更明确对于Provider的操作,我们可将它替换为context.watch<>()和context.read<>()方式。
    我们可以通过源码看到,context.watch<>()和context.read<>()方法其实都是调用Provider.of<T>(BuildContext context, {bool listen = true})来实现

     

 pubspec.yaml 中引用

provider: ^6.0.3

 

在Flutter中,context.watch<T>()context.read<T>()都是用于在Widget树中获取和监听状态的方法,它们都是来自于Flutter的状态管理库provider

  1. context.watch<T>():该方法用于订阅状态变化,并在状态发生变化时重新构建相关的Widget。当使用context.watch<T>()订阅某个类型为T的状态时,如果该状态发生变化,与该状态相关的Widget会被重新构建。

final count = context.watch<Counter>().count;

  在上面的示例中,我们使用context.watch<Counter>()订阅了类型为Counter的状态,当Counter状态发生变化时,相关的Widget会重新构建,并获取最新的count值。context.read<T>():该方法用于获取指定类型为T的状态的当前值,而不会订阅状态的变化。如果在context.read<T>()之前没有调用过相关状态的notifyListeners()方法,那么获取到的将是状态的初始值。

  

final count = context.read<Counter>().count;

  在上面的示例中,我们使用context.read<Counter>()获取了类型为Counter的状态的当前值。

总结:

  • 如果您需要在状态发生变化时自动重新构建相关的Widget,请使用context.watch<T>()来订阅状态。
  • 如果您只需要获取状态的当前值而不关心状态的变化,请使用context.read<T>()来获取状态。

  请注意,context.watch<T>()context.read<T>()都需要在Widget树中的BuildContext上下文中使用。通常,您可以在构建方法中使用这些方法。

 

    

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

// Define a counter class as a ChangeNotifier
class Counter with ChangeNotifier {
  int _count = 0;

  int get count => _count;

  void increment() {
    _count++;
    notifyListeners();
  }
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => Counter(),
      child: MaterialApp(
        home: HomePage(),
      ),
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final count = context.watch<Counter>().count;

    return Scaffold(
      appBar: AppBar(
        title: Text('Counter App'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              'Count: $count',
              style: TextStyle(fontSize: 24),
            ),
            ElevatedButton(
              onPressed: () {
                context.read<Counter>().increment();
              },
              child: Text('Increment'),
            ),
          ],
        ),
      ),
    );
  }
}

 

In this example, we define a Counter class that extends ChangeNotifier. It has a count property and an increment method that increases the count and notifies the listeners.

The MyApp widget wraps the Counter class with ChangeNotifierProvider to make it available to the rest of the app.

In the HomePage widget, we use context.watch<Counter>().count to subscribe to changes in the Counter state. Whenever the count changes, the widget will be rebuilt to reflect the updated value. We also use context.read<Counter>().increment() to call the increment method of the Counter class when the button is pressed.

This example demonstrates how to use context.watch<T>() and context.read<T>() to interact with state in Flutter using the provider package.

 

 

The line ChangeNotifierProvider(create: (_) => userProvider) is creating a provider for the userProvider object.

Here's an example to illustrate its usage:

 

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

class User {
  final String name;
  final int age;

  User(this.name, this.age);
}

class UserProvider with ChangeNotifier {
  User _user;

  User get user => _user;

  void setUser(User user) {
    _user = user;
    notifyListeners();
  }
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (_) => UserProvider(),
      child: MaterialApp(
        home: HomePage(),
      ),
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final userProvider = Provider.of<UserProvider>(context);

    return Scaffold(
      appBar: AppBar(
        title: Text('User Info'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              'Name: ${userProvider.user?.name ?? ''}',
              style: TextStyle(fontSize: 24),
            ),
            Text(
              'Age: ${userProvider.user?.age ?? ''}',
              style: TextStyle(fontSize: 24),
            ),
            ElevatedButton(
              onPressed: () {
                final newUser = User('John Doe', 30);
                userProvider.setUser(newUser);
              },
              child: Text('Set User'),
            ),
          ],
        ),
      ),
    );
  }
}

 

In this example, we have a User class representing user information. The UserProvider class is a ChangeNotifier that manages the state of the current user.

The ChangeNotifierProvider is created with create: (_) => UserProvider(). It instantiates a new UserProvider object and makes it available to the widget tree.

In the HomePage widget, we use Provider.of<UserProvider>(context) to access the UserProvider instance. We can then use userProvider.user to get the current user information and update it by calling userProvider.setUser(newUser).

By wrapping the HomePage widget with ChangeNotifierProvider, the UserProvider state will be available to all the descendant widgets that depend on it. When the state changes, the corresponding widgets will be rebuilt to reflect the updated values.

 

In the context of the create parameter in ChangeNotifierProvider, the _ represents the build context argument that is not being used.

The _ is a convention used in Dart to indicate that a variable is intentionally unused. It's a way to communicate to other developers that the value of the variable is not relevant or necessary in the given context.

In the case of ChangeNotifierProvider, the create parameter expects a callback function that takes a build context argument. However, if the callback function does not require the build context, it is common to use _ as the variable name to indicate that it is intentionally unused.