美文网首页Flutter
使用Provider进行Flutter状态管理

使用Provider进行Flutter状态管理

作者: 渣渣曦 | 来源:发表于2020-04-26 15:40 被阅读0次

    provider针对不同类型的对象提供了几种不同的“provider”,如下:

    名称 描述
    Provider 最基本的provider类型,获取一个任何类型的数据值
    ListenableProvider 提供一个Listenable的指定对象,当侦听被调用时Listenable将侦听对象和重求创建请求组件
    ChangeNotifierProvider 为ChangeNotifier提供的ListenableProvider,在需要时自动调用ChangeNotifier.dispose
    ValueListenableProvider 侦听一个ValueListenable获取ValueListenable.value
    StreamProvider 侦听一个Stream流并获取最新emitted插入值

    创建工程demo:

    flutter create flutter_demo_provider
    

    首先在pubspec.yaml里插入以下值:

    provider: ^2.0.1
    http: ^0.12.0+2
    

    新建一个名为app_state.dart文件创建 AppState的provider类:

    import 'package:flutter/material.dart';
    
    class AppState with ChangeNotifier {
      AppState();
    
      String _displayText = "";
    
      void setDisplayText(String text) {
        _displayText = text;
        notifyListeners();
      }
    
      String get getDisplayText => _displayText;
    }
    

    AppState是ChangeNotifier的扩展类,用于调用notifyListener()方法后进行广播。
    代码中两个方法setDisplayTextgetDisplayText用于读写状态值。
    使用以下代码覆盖main.dart:

    import 'package:flutter/material.dart';
    import 'package:flutter_demo_provider/app_state.dart';
    import 'package:flutter_demo_provider/text_display.dart';
    import 'package:flutter_demo_provider/text_edit.dart';
    import 'package:provider/provider.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
            title: 'Flutter Demo',
            theme: ThemeData(
              primarySwatch: Colors.blue,
            ),
            home: ChangeNotifierProvider<AppState>(
              create: (_) => AppState(),
              child: MyHomePage(),
            ));
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key}) : super(key: key);
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(),
          body: Container(
            padding: const EdgeInsets.all(16.0),
            child: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.start,
                children: <Widget>[
                  TextDisplay(),
                  TextEditWidget(),
                ],
              ),
            ),
          ),
        );
      }
    }
    

    代码中使用的ChangeNotifierProvider来源于provider插件,其封装了两个参数分别是builderchild

    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
            primarySwatch: Colors.blue,
        ),
        home: ChangeNotifierProvider<AppState>(
            create: (_) => AppState(),
            child: MyHomePage(),
        ));
    }
    

    MyHomePage -> Scaffold ->Column中有两个组件分别为TextDisplay()TextEditWidget()
    TextDisplay()在text_display.dart中定义:

    import 'package:flutter/material.dart';
    import 'package:flutter_demo_provider/app_state.dart';
    import 'package:provider/provider.dart';
    
    class TextDisplay extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        final appState = Provider.of<AppState>(context);
    
        return Container(
          padding: const EdgeInsets.all(16.0),
          child: Text(
            appState.getDisplayText,
            style: TextStyle(
              fontSize: 24.0,
            ),
          ),
        );
      }
    }
    

    其中

    Widget build(BuildContext context) {
        final appState = Provider.of<AppState>(context);
    
        return Container(
            padding: const EdgeInsets.all(16.0),
            child: Text(
            appState.getDisplayText,
            style: TextStyle(
                fontSize: 24.0,
            ),
            ),
        );
    }
    final appState = Provider.of<AppState>(context);
    

    这段代码将通过provider侦听任何变化,当然可以通过listen: false取消侦听

    final appState = Provider.of<AppState>(context, listen: false);
    

    通过调用getDisplayText方法来获取文本

    appState.getDisplayText()
    

    text_edit.dart中实现TextEditWidget()

    import 'package:flutter/material.dart';
    import 'package:flutter_demo_provider/app_state.dart';
    import 'package:provider/provider.dart';
    
    class TextEditWidget extends StatefulWidget {
      @override
      _TextEditWidgetState createState() => _TextEditWidgetState();
    }
    
    class _TextEditWidgetState extends State<TextEditWidget> {
      TextEditingController _textEditingController = TextEditingController();
    
      @override
      Widget build(BuildContext context) {
        final appState = Provider.of<AppState>(context);
    
        return Container(
          child: TextField(
            controller: _textEditingController,
            decoration: InputDecoration(
              labelText: "Some Text",
              border: OutlineInputBorder(),
            ),
            onChanged: (changed) => appState.setDisplayText(changed),
            onSubmitted: (submitted) => appState.setDisplayText(submitted),
          ),
        );
      }
    }
    

    build方法里获取appState

    final appState = Provider.of<AppState>(context);
    

    通过setDisplayText(text)函数操作文本

    TextField(
        controller: _textEditingController,
        decoration: InputDecoration(
            labelText: "Some Text",
            border: OutlineInputBorder(),
        ),
        onChanged: (changed) => appState.setDisplayText(changed),
        onSubmitted: (submitted) => appState.setDisplayText(submitted),
    )
    

    在文本框变更时更新状态

    onChanged: (changed) => appState.setDisplayText(changed)
    
    1_UtYFKuL0vo2HxJ200zWL2g.gif

    通过地址进行数据源请求

    AppState中增增加方法和变量

    String _dataUrl = "https://reqres.in/api/users?per_page=20";
    String _jsonResonse = "";
    bool _isFetching = false;
    
    bool get isFetching => _isFetching;
    
    Future<void> fetchData() async {
        _isFetching = true;
        notifyListeners();
    
        var response = await http.get(_dataUrl);
        if (response.statusCode == 200) {
            _jsonResonse = response.body;
        }
    
        _isFetching = false;
        notifyListeners();
    }
    
    String get getResponseText => _jsonResonse;
    
    List<dynamic> getResponseJson() {
        if (_jsonResonse.isNotEmpty) {
            Map<String, dynamic> json = jsonDecode(_jsonResonse);
            return json['data'];
        }
        return null;
    }
    

    AppState中增加了fetchDatagetResponseTextgetResponseJson
    fetchData进行网络请求和更新响应数据的变量(解析JSON在自定义的model中并保存在List里)。
    getResponseText返回响应文本。
    getResponseJson转换响应文本到一个Map类型并返回其中data的一个Map列表数据。
    最终的app_state.dart代码如下:

    import 'package:flutter/material.dart';
    import 'package:http/http.dart' as http;
    import 'dart:convert';
    
    class AppState with ChangeNotifier {
      String _dataUrl = "https://reqres.in/api/users?per_page=20";
    
      AppState();
    
      String _displayText = "";
      String _jsonResonse = "";
      bool _isFetching = false;
    
      void setDisplayText(String text) {
        _displayText = text;
        notifyListeners();
      }
    
      String get getDisplayText => _displayText;
    
      bool get isFetching => _isFetching;
    
      Future<void> fetchData() async {
        _isFetching = true;
        notifyListeners();
    
        var response = await http.get(_dataUrl);
        if (response.statusCode == 200) {
          _jsonResonse = response.body;
        }
    
        _isFetching = false;
        notifyListeners();
      }
    
      String get getResponseText => _jsonResonse;
    
      List<dynamic> getResponseJson() {
        if (_jsonResonse.isNotEmpty) {
          Map<String, dynamic> json = jsonDecode(_jsonResonse);
          // print(json['data']['avatar']);
          return json['data'];
        }
        return null;
      }
    }
    

    MyHomePage中增加两个组件到column

    RaisedButton(
        onPressed: () => appState.fetchData(),
        child: Text("Fetch Data from Network"),
    ),
    ResponseDisplay(),
    

    当点击按钮后调用appState.fetchData()fetchData会更新状态

    import 'package:flutter/material.dart';
    import 'package:flutter_demo_provider/app_state.dart';
    import 'package:flutter_demo_provider/response_display.dart';
    import 'package:flutter_demo_provider/text_display.dart';
    import 'package:flutter_demo_provider/text_edit.dart';
    import 'package:provider/provider.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
            title: 'Flutter Demo',
            theme: ThemeData(
              primarySwatch: Colors.blue,
            ),
            home: ChangeNotifierProvider<AppState>(
              create: (_) => AppState(),
              child: MyHomePage(),
            ));
      }
    }
    
    class MyHomePage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        final appState = Provider.of<AppState>(context);
    
        return Scaffold(
          appBar: AppBar(),
          body: SingleChildScrollView(
            child: Container(
              padding: const EdgeInsets.all(16.0),
              child: Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.start,
                  children: <Widget>[
                    TextDisplay(),
                    TextEditWidget(),
                    RaisedButton(
                      onPressed: () => appState.fetchData(),
                      child: Text("Fetch Data from Network"),
                    ),
                    ResponseDisplay(),
                  ],
                ),
              ),
            ),
          ),
        );
      }
    }
    

    ResponseDisplay组件定义命名为response_display.dart

    import 'package:flutter/material.dart';
    import 'package:flutter_demo_provider/app_state.dart';
    import 'package:provider/provider.dart';
    
    class ResponseDisplay extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        final appState = Provider.of<AppState>(context);
    
        return Container(
          padding: const EdgeInsets.all(16.0),
          child: appState.isFetching
              ? CircularProgressIndicator()
              : appState.getResponseJson() != null
                  ? ListView.builder(
                      primary: false,
                      shrinkWrap: true,
                      itemCount: appState.getResponseJson().length,
                      itemBuilder: (context, index) {
                        return ListTile(
                          leading: CircleAvatar(
                            backgroundImage: NetworkImage(
                                appState.getResponseJson()[index]['avatar']),
                          ),
                          title: Text(
                            appState.getResponseJson()[index]["first_name"],
                          ),
                        );
                      },
                    )
                  : Text("Press Button above to fetch data"),
        );
      }
    }
    

    text_edit.dart使用以下代码替换

    import 'package:flutter/material.dart';
    import 'package:flutter_demo_provider/app_state.dart';
    import 'package:provider/provider.dart';
    
    class TextEditWidget extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
            final appState = Provider.of<AppState>(context);
    
        return Container(
          child: TextField(
            // controller: _textEditingController,
            decoration: InputDecoration(
              labelText: "Some Text",
              border: OutlineInputBorder(),
            ),
            onChanged: (changed) => appState.setDisplayText(changed),
            onSubmitted: (submitted) => appState.setDisplayText(submitted),
          ),
        );
      }
    }
    

    显示结果如下图:


    1_B-ZCyKgTOu5Hn8vvwNkTRQ.gif
    1_TCwHjTu0PhC_4Ow8DgImBw.gif

    原文地址(需翻墙)

    相关文章

      网友评论

        本文标题:使用Provider进行Flutter状态管理

        本文链接:https://www.haomeiwen.com/subject/dewdwhtx.html