Flutter_功能Flutter

Flutter状态管理Provider(一)

2019-06-17  本文已影响0人  简wen

       Google2019I/O大会上被谷歌推荐,原本谷歌的provide被弃用,与大部分状态管理一样使用了InheritedWidget。基于Provider3.0
第二篇Flutter状态管理Provider(二)

Provider()

两种方式Provider()和Provider.value(),使用基本差不多,区别在于Provider()提供dispose参数,可以在传递一个方法销毁的时候被调用,方便StatelessWidget释放资源,使用Provider写一个bloc


1794647-cf4839d4dccb3bab_gaitubao_300x555.gif
import 'dart:async';

class CountBloc {
  final StreamController<int> _countController = StreamController();
  int count = 0;
  Stream<int> stream;

  CountBloc() {
    stream = _countController.stream.asBroadcastStream();
  }

  add() {
    _countController.add(++count);
  }

  //关闭
  dispose() {
    _countController?.close();
  }
}

界面代码

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

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    //如果状态管理放在顶层 MaterialApp 之上,它的作用域是全局,任何界面都可以获取;
    return Provider<CountBloc>(
      builder: (context) => CountBloc(),
      //dispose:在widget销毁的时候调用,方便关闭stream,可以防止内存泄露
      //特别是在在StatelessWidget中使用非常好,因为StatelessWidget没有dispose方法
      dispose: (context, value) => value.dispose(),
      child: MaterialApp(
        title: "provider",
        home: HomePage(),
      ),
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("HomePage")),
      body: StreamBuilder(
          stream: Provider.of<CountBloc>(context).stream,
          initialData: 0,
          builder: (context, snapshot) {
            return Center(child: Text("${snapshot.data}"));
          }),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Navigator.push(
              context, MaterialPageRoute(builder: (context) => SecondPage()));
        },
        child: Icon(Icons.arrow_forward_ios),
      ),
    );
  }
}

class SecondPage extends StatefulWidget {
  @override
  _SecondPageState createState() => _SecondPageState();
}

class _SecondPageState extends State<SecondPage> {
  @override
  Widget build(BuildContext context) {
    CountBloc bloc = Provider.of<CountBloc>(context);
    return Scaffold(
      appBar: AppBar(title: Text("第二页")),
      body: StreamBuilder(
          stream: bloc.stream,
          initialData: bloc.count,
          builder: (context, snapshot) {
            return Center(child: Text("${snapshot.data}"));
          }),
      floatingActionButton: FloatingActionButton(
        onPressed: () => bloc.add(),
        child: Icon(Icons.add),
      ),
    );
  }
}
  1. 下面使用ValueListenableProvider,它只支持单一数据的监听,有两种方式,一种ValueListenableProvider.value(),另一种ValueListenableProvider(),两种方式几乎是相同的。
    先介绍下Consumer和Provider:
//此方法将从BuildContext关联的小部件树中查找,它将返回找到的最近的类型变量T
Provider.of<T>( BuildContext context,
     {bool listen = true}//listen:默认true监听状态变化,false为不监听状态改变
)
//也可以使用Consumer组件获取,Consumer可用在没有context的地方,还可以优化性能
Consumer<T>({
    @required this.builder,//这边写布局
    this.child,//可以控制刷新性能优化,当数据数据发生改变,不会重新build,
  })
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "provider",
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    ValueNotifier<int> count = ValueNotifier(0);
    //在HomePage里面写状态,它的作用域只在HomePage中
    return Scaffold(
      appBar: AppBar(title: Text("home")),
      body: ValueListenableProvider.value(
        value: count,
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            LeftView(), CenterView(), RightView()
          ],
        ),
      ),
      floatingActionButton:
          FloatingActionButton(onPressed: () => count.value += 1,child: Icon(Icons.add),),
    );
  }
}

class LeftView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("LeftView:build");
    return Consumer<int>(
        child: MyText(),
        builder: (context, value, child) {
          return Container(
              width: 100,
              height: 100,
              color: Colors.blue,
              alignment: Alignment.center,
              child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[child, Text("$value")]));
        });
  }
}

class MyText extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("MyText:build");
    return Text("数量");
  }
}

class CenterView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("CenterView:build");
    return Container(
      width: 100,
      height: 100,
      color: Colors.pink,
      alignment: Alignment.center,
      child: Text(
        //listen: false 不监听状态改变
        "数量\n${Provider.of<int>(context, listen: false)}",
        textAlign: TextAlign.center,
      ),
    );
  }
}

class RightView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("RightView:build");
    return Container(
      width: 100,
      height: 100,
      color: Colors.green,
      alignment: Alignment.center,
      child: Text(
        "数量\n${Provider.of<int>(context)}",
        textAlign: TextAlign.center,
      ),
    );
  }
}
1794647-31a67f0a79b6b742_gaitubao_300x801.gif

1、观察日志发现蓝色LeftView和MyText初始化后没有重新build。
2、红色CenterView初始化后也没有重新build
3、绿色RightView会随着状态改变会重新build
总结使用Consumer可以有效的优化性能,使用ValueListenableProvider时Provider.of<T>()获取部件树中状态同时也可以监听状态改变从而刷新部件。

上一篇 下一篇

猜你喜欢

热点阅读