Flutter中的状态持久化以及状态管理

前文

本文所提供的的状态管理的方法为provide以及provider这两种,后续如果我使用了redux或state的话,就再来给大家分享

Flutter状态持久化

目的
在我们日常开发中,每次点击tab页面后,都会出现从新加载当前页面内容的现象,这种体验给用户看来很不友好,所以我们这里就需要用到了Flutter状态持久化。

两种状态持久化的方法

  • IndexedStack控件
  • AutomaticKeepAliveClientMixin

IndexedStack
原理:将所有的页面都放到IndexStack当中,通过控制index属性,来显示哪个页面(前端的小伙伴可以利用z-index来理解)
弊端:每一次加载APP的时候,都要将所有的页面加载出来,才能达到页面保持状态的效果

原理图:
Flutter中的状态持久化以及状态管理_第1张图片

如何使用?
在你的bottomNavigationBar页面中,我们的body本来是控制显示首页的,现在我们用IndexedStack替换一下,下图中的pageList是我的页面数组
Flutter中的状态持久化以及状态管理_第2张图片

AutomaticKeepAliveClientMixin
结合tab切换保持页面状态相比IndexedStack而言配置起来稍微有些复杂,是结合BottomNavigationBar保持页面状态的时候进行配置的
原理:还没搞懂。。。。。
如何使用?

  1. 首先实例化pageController,将BottomNavigationBar的 currentIndex值传给pageController
    Flutter中的状态持久化以及状态管理_第3张图片
  2. 在body入口 用PageView包裹住,设置好controller参数为实例化的值,children则为页面数组
    这里说明一下,如果用PageView包裹住的话,tab页切换就会有滑动切换的效果,所以这里我们要设置一下onPageChanged方法,这样底部标签栏就可以跟随切换而高亮了,下图中由于疏忽忘记写了,特附赠这段代码
body: PageView(
          controller: this._pageController,
          children: this.pageList,
          onPageChanged: (index){
            setState(() {
             this._currentIndex = index; 
            });
          },
        ),
  1. 切换页面的时候,通过BottomNavigationBar的onTap方法跳转页面,调用jumpToPage(index) 传入index值 跳转
    Flutter中的状态持久化以及状态管理_第4张图片
  2. 子类都要通过with关键字混合继承AutomaticKeepAliveClientMixin;
    同时重写wantKeepAlive方法,返回true
    Flutter中的状态持久化以及状态管理_第5张图片

OK,到此为止了, 状态化管理目前就这两种,大多数使用的是第二种,推荐第二种!

Flutter状态管理之Provide

flutter_provide是Google项目下的状态管理,推荐使用这个插件
关于Flutter的状态管理,我是用前端的Vuex去理解的,是将UI层和逻辑层分开的操作。

如何使用?
首先你要做的是在pubspec.yaml引入provide插件。

provide: ^1.0.2                             #状态管理

安装完毕后,我们就可以使用了,首先要写个状态管理类,也就是逻辑层的类
,我创建的文件名为test.dart

test.dart

import 'package:flutter/material.dart';

// 将页面的业务逻辑 分到当前dart文件中

// ChangeNotifier 不限制类的获取,谁都可以获取当前类
class Counter with ChangeNotifier {
  int currentIndex = 0;

  int index = 0;

  changeIndex(index){
    currentIndex = index;
    // 可以通知听众。局部刷新Widget
    notifyListeners();
  }

  increment(){
    index++;
    notifyListeners();
  }
}

创建好类之后,我们就将该状态管理引入到我们的main.dart入口文件当中,同时记得要引入provide插件

import 'package:provide/provide.dart';          // 状态管理
import 'package:project/provide/test.dart';

引入进来后,我们来将该类以及provide实例化,这里需要注意的是,实例化的时候是Providers(),并不是Provider(),最后在runApp()当中将provider注册进去

void main() {
  var counter = Counter();
  var providers = Providers();
	
// 如果想添加新的状态管理,在下面通过..添加就行
  providers..provide(Provider<Counter>.value(counter))

  runApp(ProviderNode(child:MyApp(), providers:providers));
}

好了,现在我们准备工作已经完事了,接下来我们来看看如何使用吧

import 'package:flutter/material.dart';
import 'package:provide/provide.dart';
import 'package:project/provide/BottomNavigation.dart';

class MessagePage extends StatefulWidget {
  @override
  _MessagePageState createState() => _MessagePageState();
}

class _MessagePageState extends State<MessagePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        width: double.infinity,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            // Text('消息')
            ShowText(),
            Button()
          ],
        ),
      )
    );
  }
}

class ShowText extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Provide<Counter>(
        // counter 是自定义逻辑类
        builder: (context, child, counter){
          return Text(
            '${counter.index}',
            style: Theme.of(context).textTheme.display1,
          );
        },
      )
    );
  }
}

class Button extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      child: Text('增加'),
      onPressed: (){
        // 调用改变状态方法
        Provide.value<Counter>(context).increment();
      },
    );
  }
}

代码分析:
在我们需要保持状态管理的地方,利用Provider控件包裹起来,在调用builder方法 将控件返回出来,里面有三个参数,第一个是上下文,第二个是子类,第三个是状态管理类,我们通过第三个参数就可以访问到我们的属性值了,改变的方法也是通过value方法来调用管理类定义好的方法,这里的value记得声明泛型来指明我们的状态管理类。

Flutter状态管理之Provider

provider是也是在谷歌项目下的状态管理,作用和provide都是一样的,用于管理全局的数据状态
如何使用?
首先你要做的是在pubspec.yaml引入provider插件。

provider: ^3.2.0

创建自定义状态管理类Count.dart

import 'package:flutter/material.dart';

class Counter with ChangeNotifier{
  int _count;     // 状态

  // 实例化时就初始化数据
  Counter(){
    this._count = 0;
  }

  int get count=>_count;      // 获取当前状态(为什么已经有个变量了,还要再写一个变量赋值抛出去呢: 保护变量,避免状态管理类被污染)

  incCount(){
    this._count++;
    notifyListeners();    // 通知更新状态 
  }
}

main.dart中使用MultiProvider控件包裹住所有内容,同时设置属性providers进行监听状态管理

import 'package:flutter/material.dart';
import 'package:test_03/router/routes.dart';		// 自定义路由

import 'package:provider/provider.dart';		// 状态管理
import 'package:test_03/provider/Count.dart';		// 自定义状态管理

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_)=>Counter()),		// 监听自定义的类
      ],
      child: MaterialApp(
        initialRoute: '/',
        routes: routers,
        onGenerateRoute: onGenerateRoute,
      ),  
    );
  }
}

接下来就是在各个类中使用了,由于已经在main.js中用控件包裹住一层了,所以不需要像provide一样,还需要再次嵌套控件了,只需要在您需要使用的类中引入您的provider插件以及自定义的状态管理类就可以了。

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

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {
  String data = "init";
  @override
  Widget build(BuildContext context) {
	
	//  是泛型指定自定义状态类
    var counterProvider = Provider.of<Counter>(context);	

    return Scaffold(
      body: ListView(
        children: <Widget>[
          Text(data),
          Text('${counterProvider.count}'),
          RaisedButton(
            child: Text('点击修改状态管理中的数据'),
            onPressed: (){
              counterProvider.incCount();
            },
          ),
        ],
      ),
  }
}

同理如果别的页面也需要这个状态数据,就像这样引入就可以共用了

provider和provide的区别

不同之处

1、作者
provide:Flutter早期没有自己的状态管理类,由Google的一名开发人员开发写出的一款插件
provider:Flutter官方团队提供的官方插件
2、使用
provide
(1)需要在main.dart中的void main(){ }主函数方法中进行初始化和注册。
(2)各个dart类使用的时候需要在外层再次包裹一层Provide的控件
provider
(1)只需在main.js中的主控件外部包裹一层MultiProvider控件,把providers声明好属性就可以在内部使用了。

相同之处

在自定义状态管理类时,都是混合使用的flutter内部提供的ChangeNotifier类,在通知时都是使用的notifyListeners()方法

OK! 彻底完结,有问题@我哦,告辞┏(^0^)┛

你可能感兴趣的:(Flutter,Flutter状态管理,Flutter状态持久化,Provide,Provider)