Flutter

使用Provider进行Flutter状态管理

2020-04-26  本文已影响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

原文地址(需翻墙)

上一篇下一篇

猜你喜欢

热点阅读