Flutter Provider status management -Consumer

Foreword

If Consumer very understanding of students can continue learning  Flutter Provider state management - Selector

Flutter personally I feel that there are three very important learning stage

  1. widget to learn and use
  2. Data management and state
  3. And interact with native

On the first point Needless to say, when we began to learn flutter are followed by the official website or blog to learn how to use the widget and a widget combined into a colorful interface. If you do not learn the students can go Flutter Chinese network started.

Widget is simple to learn, even if not familiar with the widget we just need to see the constructor and the corresponding annotation attributes about 80% will be able to get to know, and we write a page like writing configuration files, and then handed over to flutter bottom to deal with just fine. But we have to interface with the data Yeah, flutter data management is a science, many students beginning with flutter access data did not know the data on there, what the entire project with the framework and so on. . . . At first I have encountered this problem, see the Internet, said busy fish fish-redux framework is very good, the data and UI is completely isolated, and it uses a data-driven way the UI (like MVVM framework), but as a white redux framework when I went to study fish-redux of force to rip off my face. . . . . .

This stuff is too complicated, right, split super fine granularity, something my uncle be able to achieve a class you get me some five or six out and said what multiplexing. . . . . Moreover, I am writing are small demo Yeah, with this it not slaughter chickens Yanyong chopper ( solemnly declare: do not deny Niubi place fish-redux of large projects use may really wonders )

Fortunately, there are how Provider, this framework also say google official recommendation, there will be no difference!

Say why you want to use state management:

We all know that flutter in to change the page is very simple, just setState on it, but the code calling this method is extremely expensive, will lead us to redraw the entire page, a simple "counters" do not say, even if we are also less likely to have been setState sense pages Caton, but if we put the page into the "Taobao", "Yidong" this complex pages? You change a button text will lead to redraw the entire page, the code is not too large. . .

Ado, let's look at the use of Provider:

1. INTRODUCTION package

dependencies:
  provider: ^3.1.0+1

Say one more thing: It is strongly recommended to use version 3.1.0 or later, for reasons Well, there are follow-up time will be mentioned

2. using the most simple counter code to integrate provider

There are three documents

Entrance 2.1 main.dart this goes without saying, the program


class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    ///这里用到了MultiProvider,针对多个Provider的使用场景
    ///在这里我们初始化了CounterProvider并且指定了child为MaterialApp
    return MultiProvider(
      providers: [ChangeNotifierProvider(builder: (_) => CounterProvider())],
      child: MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          // This is the theme of your application.
          //
          // Try running your application with "flutter run". You'll see the
          // application has a blue toolbar. Then, without quitting the app, try
          // changing the primarySwatch below to Colors.green and then invoke
          // "hot reload" (press "r" in the console where you ran "flutter run",
          // or simply save your changes to "hot reload" in a Flutter IDE).
          // Notice that the counter didn't reset back to zero; the application
          // is not restarted.
          primarySwatch: Colors.blue,
        ),
        routes: {
          Routes.INDEX_PAGE: (context) => IndexPage(),
          Routes.STOCK_LIST_PAGE: (context) => StockListPage(),
          Routes.QRCODE_SCAN_PAGE: (context) => QrCodeScanPage(),
          Routes.LOGIN: (context) => LoginPage(),
          Routes.SPLASH: (context) => SplashPage(),
          Routes.MY_APP: (context) => MyPage()
        },
        initialRoute: Routes.MY_APP,
      ),
    );
  }
}

In the program we use MultiProvider entrance wrapped in a layer, and initialized CounterProvider, the child designated as MaterialApp.

Note: Not recommended program entry in the initialization Provider, here only to demonstrate convenient to do so, and if the actual project may result in a sharp increase in memory initialization program entry, unless it is shared some global state, such as app on the night mode switching, in English switching. . . .

2.2 CounterProvider

class CounterProvider with ChangeNotifier {
  int _count = 0;

  int get value => _count;

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

This class does three things:

  1. Inherited from ChangeNotifier
  2. Initialization count is 0 (which is why we want to provide out data), and provides a get method
  3. Declaring a function to change the increment value of the count, and each change will trigger notifyListeners (), the role of this method is to inform CounterProvider host my values ​​have changed

2.3 my_page.dart

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

import 'counter_provider.dart';

class MyPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => MyPageState();
}

class MyPageState extends State<MyPage> {

  @override
  Widget build(BuildContext context) {
    //获取CounterProvider
    CounterProvider counterProvider = Provider.of<CounterProvider>(context);

    print('页面重绘了。。。。。。。。。。。');

    return Scaffold(
      appBar: AppBar(
        title: Text('my page'),
      ),
      body: Center(
          child: Text(
            //获取数据
            'value: ${counterProvider.value}',
            style: TextStyle(fontSize: 20),
          )),
      floatingActionButton: FloatingActionButton(
          child: Icon(Icons.navigation),
          onPressed: () {
            //调用increment方法改变数据
            counterProvider.increment();
          }),
    );
  }
}

Ah ha ha, and finally to the UI, we see our familiar Widget, the code is very simple, the main three steps:

  1. Acquired in the program entry (main.dart) initialization method in the build CountProvider
  2. Click the button to call the increment method, change the value of count
  3. Gets the value of count in text

As the Provider is data-driven UI, so we just need to fill in values, UI will automatically refresh. Indeed been tested and found to achieve our desired results, every click of a button will add a text value.

But do not forget we said at the beginning: We use state management of the most important is to solve the problem of redrawing the entire page!

In the above demo, we only want the widget to redraw Text, after all, its value is changed, but the button and we do not want to redraw appbar, so we added the print statement, if every time I click on the button will print "redraw the page ......" that is a very boring thing, that the truth is what?

True TM print, that we still Provider diao use?

Do not worry, listen to me slowly to say:

We in the code is the use of Provider.of to get CounterProvider, this approach does get in will cause redraw the entire page, as for reasons beyond the scope of this chapter, after a time to talk. So Provider in the end can not be achieved "partial refresh" ? Of course it is possible, otherwise the framework is really nothing to use. Here we come to know a heavyweight guests:

3.Cosumer

In this section we follow the code counter, to be rehabilitated. Before we mentioned in the program initialization Provider entrance is very irregular, so we changed the page level initialization, combined with the Consumer to use. So we remaining two files, CountProvider and MyPage

3.1 CountProvider

And exactly the same as before, no change! ! ! !

3.2 MyPage

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

import 'counter_provider.dart';

class MyPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => MyPageState();
}

class MyPageState extends State<MyPage> {
  ///初始化CounterProvider
  CounterProvider _counterProvider = new CounterProvider();

  @override
  Widget build(BuildContext context) {
    print('页面重绘了。。。。。。。。。。。');

    //整个页面使用ChangeNotifier来包裹
    return ChangeNotifierProvider(
      builder: (context) => _counterProvider,
      child:
          //child里面的内容不会因为数据的改变而重绘
          Scaffold(
        appBar: AppBar(
          title: Text('my page'),
        ),
        body: Center(child:
            //使用Cousumer来获取Provider
            Consumer(builder: (BuildContext context,
                CounterProvider counterProvider, Widget child) {
          print('Text重绘了。。。。。。');
          return Text(
            //获取数据
            'value: ${counterProvider.value}',
            style: TextStyle(fontSize: 20),
          );
        })),
        floatingActionButton: FloatingActionButton(
            child: Icon(Icons.navigation),
            onPressed: () {
              //调用increment方法改变数据
              _counterProvider.increment();
            }),
      ),
    );
  }
}

Slightly more complicated point, patience to watch

  1. We CounterProvider initialization mentioned MyPageState
  2. ChangeNotifierProvider used to wrap the entire page, and specifies the data source is CounterProvider
  3. Provider way of acquiring abandoned before using to get the Consumer

Let me talk Conclusion: the above code to run and does not lead to redraw the entire page, just Text will redraw, do not believe you can see:

Then we will say a few areas of doubt

1. MultiProvider and ChangeNotifierProvider to initialize any different?

const MultiProvider({
    Key key,
    //list
    @required this.providers,
    this.child,
  })  : assert(providers != null),
        super(key: key);
ChangeNotifierProvider({
    Key key,
    @required ValueBuilder<T> builder,
    Widget child,
  }) : super(key: key, builder: builder, dispose: _disposer, child: child);

MultiProvider received parameter is a List, then use it if the current page of data from multiple Provider to initialize, such as we in the "my" page may want to display user information (UserProvider) and order information (OrderProvider)

ChangeNotifierProvider is simple, just specify a single Provider

The difference 2.ChangeNotifierProvider and ChangeNotifierProvider.value

  ChangeNotifierProvider({
    Key key,
    @required ValueBuilder<T> builder,
    Widget child,
  }) : super(key: key, builder: builder, dispose: _disposer, child: child);

  /// Provides an existing [ChangeNotifier].
  ChangeNotifierProvider.value({
    Key key,
    @required T value,
    Widget child,
  }) : super.value(key: key, value: value, child: child);
}

ChangeNotifierProvider (builder pattern) parent class constructor a more a disposer, when ChangeNotifierProvider widget is removed from the tree will automatically call dispose method to remove the corresponding data, such that the memory occupied always maintained a reasonable level.

ChangeNotifierProvider.value not automatically called when the widget is removed tree dispose, need to manually manage data in this way for some of the old hands, such as when they were removed elsewhere still want to use this data, and at the right when the need to manually shut down.

widget under 3.ChangeNotifierProvider the child parameters will not change the data and redraw page

The above code, we put all related UI widget are placed below the child, why only Text changed? Consumer because we used to wrap, so apart from something other than the Consumer will not be redrawn, which is why Provider can do partial refresh UI.

So when we use the Consumer Package contents of granularity to be as fine as possible, and if that is equivalent to the global direct wrapped useless Provider.

4. How to use a plurality of Provider Consumer obtain

We use the example of the Consumer counter gained only CounterProvider to provide data to Text, but the actual development of our business scenario will certainly be very complicated, use Consumer wrapped widget requires multiple Provider supposed to provide data? For example, we need to show the Text count (from CounterProvider), as well as username (from UserProvider)

Provider of course, the author of this in mind, it offers a variety of Consumer to adapt to different scenarios

From Consumer - Consumer6, you can get up to a one-time six Provider, if you want to get 7 it? Sorry, I did not in this way, and only self-reliance. . . . .

In fact, I think the way to achieve this is not elegant, but six kinds have been able to meet 99% of the usage scenarios!

Consumer grasp is not enough, you need  Flutter Provider state management - Selector , a combination of both more efficient!

Conclusion: For those unfamiliar Provider students, although the above example is very simple talking about, you may have read, but be sure to practice a lot, there are many pit is the need to explore their own, so as to ease in the practical application

If you do not know where please leave a message, wrong place please correct me

 

 

 

 

 

Published 21 original articles · won praise 21 · views 20000 +

Guess you like

Origin blog.csdn.net/u013894711/article/details/102782366