Flutter狀態管理Provider,簡單上手

天玉發表於2019-06-13

學習Flutter一段時間了,偶然看到大家都說狀態管理,多數人都是用redux,對於一個Android開發人員來說之前根本沒接觸過,於是開始瞭解redux,之後又瞭解閒魚推出的fish_redux,然後又看到Vadaski發表的一系列關於Flutter狀態管理的文章,包括Scoped Model, Redux, BLoC,RxDart,provide(想了解的可以移步),看的是眼花繚亂。對於Redux,能看懂是怎麼寫的,但真要到應用的層面,感覺還是有些吃力,更不知道怎樣維護好它,一時間也不知道用什麼什麼適合自己。後來又接觸到google推薦的Provider,於是學習了下。接下來就用Provider來實現一個計數的例子。

第一步,新增Provider依賴

provider: ^2.0.1+1
複製程式碼

pub地址:pub.dev/packages/pr…

第二步,建立Model

import 'package:provider/provider.dart';
class Counter with ChangeNotifier {//1
  int _count;
  Counter(this._count);

  void add() {
    _count++;
    notifyListeners();//2
  }
  get count => _count;//3
}
複製程式碼

簡單的一個Counter物件,裡面只有一個欄位_count

  1. 這裡需要混入ChangeNotifier
  2. 寫一個增加的方法,然後需要呼叫notifyListeners();這個方法是通知用到Counter物件的widget重新整理用的。
  3. get方法

第三步,使用ChangeNotifierProvider

通常main()方法是這麼寫

main() {
  runApp(MyApp());
}
複製程式碼

我們要監聽改變就要在MyApp()外面套一層,這個是全域性的,於是如下

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

main() {
  runApp(ChangeNotifierProvider<Counter>.value(//1
    notifier: Counter(1),//2
    child: MyApp(),
  ));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      title: "Provider",
      home: HomePage(),
    );
  }
}

複製程式碼
  1. ChangeNotifierProvider呼叫value()方法,裡面傳出notifierchild
  2. notifier設定了預設的Counter(1)

當然Provider不止提供了ChangeNotifierProvider,還有Provider,ListenableProvider,ValueListenableProvider,StreamProvider, 具體可以看wiki. 如果想管理多個物件可以用MultiProvider,如下

MultiProvider(
  providers: [
    Provider<User>.value(value: user),
    Provider<Goods>.value(value: goods),
    .....
  ],
  child: someWidget,
)
複製程式碼

第四步,使用Provider獲取Counter的值

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

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text("Home"),
        actions: <Widget>[
          FlatButton(
            child: Text("下一頁"),
            onPressed: () =>
                Navigator.push(context, MaterialPageRoute(builder: (context) {
                  return SecondPage();
                })),
          ),
        ],
      ),
      body: Center(
        child: Text("${Provider.of<Counter>(context).count}"),//1
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Provider.of<Counter>(context).add();//2
        },
        child: Icon(Icons.add),
      ),
    );
  }
}
複製程式碼
  1. Provider.of<Counter>(context).count獲取_count的值,Provider.of<T>(context)相當於Provider去查詢它管理的Counter(1)
  2. Provider.of<Counter>(context).add();呼叫Counter()中的add()方法

同樣第二個頁面也這樣寫,如下

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text("SecondPage"),
      ),
      body: Center(
        child: Text("${Provider.of<Counter>(context).count}"),//1
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Provider.of<Counter>(context).add();//2
        },
        child: Icon(Icons.add),
      ),
    );
  }
}
複製程式碼

這樣,當每個頁面都點選+號按鈕時,_count便會+1,同時通知並更新到使用它的地方。

完整程式碼,copy後可直接執行

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

main() {
  runApp(ChangeNotifierProvider<Counter>.value(
    notifier: Counter(1),
    child: MyApp(),
  ));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      title: "Provider",
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text("Home"),
        actions: <Widget>[
          FlatButton(
            child: Text("下一頁"),
            onPressed: () =>
                Navigator.push(context, MaterialPageRoute(builder: (context) {
                  return SecondPage();
                })),
          ),
        ],
      ),
      body: Center(
        child: Text("${Provider.of<Counter>(context).count}"),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Provider.of<Counter>(context).add();
        },
        child: Icon(Icons.add),
      ),
    );
  }
}

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text(Provider.of<String>(context)),
      ),
      body: Center(
        child: Text("${Provider.of<Counter>(context).count}"),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Provider.of<Counter>(context).add();
        },
        child: Icon(Icons.add),
      ),
    );
  }
}

class Counter with ChangeNotifier {

  int _count;

  Counter(this._count);

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

  get count => _count;
}
複製程式碼

總結

看了那麼多狀態管理的,個人感覺Provider還是屬於簡單易用的,並且是google推薦的。但感覺還需要成長,讓大家認可。我這裡只是一個簡單的使用,有一些地方也沒講太清楚還請大家見諒,同時也希望和各位學習Flutter的同學互相交流進步。

相關文章