(轉)flutter 新狀態管理方案 Provide (一)-使用


flutter 新狀態管理方案 Provide (一)-使用

版權聲明:本文爲博主原創文章,基於CC4.0協議,首發於https://kikt.top ,同步發於csdn,轉載必須註明出處! https://blog.csdn.net/qq_28478281/article/details/87858386

開這篇文章是由於看到這個庫被託管在google的倉庫下,並且說明是被設計出來替代ScopedModel的,並且更加靈活java

支持Builder模式和StreamBuilder模式,全局,局部均可以git

內部應該是結合InheritedWidget Notification體系實現的github

傳統的bloc須要在每個Repository中建立StreamControllerStream,甚至有的文章中,一個監聽的修改須要修改5處,維護起來比較麻煩markdown

相比較而言Provide維護起來會稍微省事一些app

入門級倉庫地址ide

添加依賴

查看pub-installpost

dependencies:
  provide: ^1.0.1 # 這裏的版本查看官方

flutter packages getui

import 'package:provide/provide.dart';

使用方法

這裏以簡單的Counter爲例
也就是在flutter的hello world工程的基礎上來修改this

1. 定義一個Model

這個model須要繼承ChangeNotifiergoogle

class Counter with ChangeNotifier {
  int _value;

  int get value => _value;

  Counter(this._value);

  void inc() {
    _value++;
    notifyListeners(); //父類的方法,發出通知
  }
}

2. 定義一個全局的Provide

這裏雖然定義在全局,但事實上也能夠定義在頁面級

void main() {
  var providers = Providers()..provide(Provider.function((ctx) => Counter(0)));

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

 

 

ProviderNode表示的是提供者

3. 界面/監聽

修改_MyHomePageState

添加一個方法,用於獲取Counter實例

Counter get _counter => Provide.value<Counter>(context);

將原來的Text(_counter)修改一下

這裏的Provide會在Counter發生變化的時候,觸發builder回調來更新界面

Provide<Counter>(
    builder: (BuildContext context, Widget child, Counter counter) {
        return Text(
            '${counter.value}',
            style: Theme.of(context).textTheme.display1,
        );
    },
),

 

 

4. 發出通知

接着就是發出通知了

修改floatingActionButton的點擊事件

floatingActionButton: FloatingActionButton(
  onPressed: () => _counter.inc(),
  tooltip: 'Increment',
  child: Icon(Icons.add),
),

 

這裏調用第三步獲取的那個Counter,而後調用inc方法


看到這裏,若是以前用過ScopedModel的朋友會問了,這個不是和之前同樣嗎,我爲啥要改呢

繼續修改

5. Stream模式

這個就很相似於bloc了,只不過model不太同樣

添加一個StreamBuilder

StreamBuilder<Counter>(
  initialData: _counter,
  stream: Provide.stream<Counter>(context),
  builder: (BuildContext context, AsyncSnapshot<Counter> snapshot) {
    return Text(
      '${snapshot.data.value}',
      style: Theme.of(context).textTheme.display1,
    );
  },
),

 

這裏initialData是第三步建立的那個,stream是使用Provide.stream<Counter>(context)獲取的

scope

provide中有一個概念叫scope,類的完整類名叫ProviderScope

class ProviderScope {
  final String _name;

  /// Constructor
  const ProviderScope(this._name);

  @override
  String toString() {
    return "Scope ('$_name')";
  }
}

 

這個類的做用就是標識Provider的區域,或者能夠理解爲給Provider/Provide定義一個做用區域

只有scope相同的才能夠識別

將state的代碼修改一下

class _MyHomePageState extends State<MyHomePage> {
  Counter get _counter => Provide.value<Counter>(context);

  PageCounter pageCounter = PageCounter(0);
  PageCounter pageCounter2 = PageCounter(0);
  var scope1 = ProviderScope("1"); 
  var scope2 = ProviderScope("2");
  @override
  Widget build(BuildContext context) {
    return ProviderNode(
      providers: Providers()
        ..provide(Provider.value(pageCounter), scope: scope1)
        ..provide(Provider.value(pageCounter2), scope: scope2),
      child: Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(
                'You have pushed the button this many times:',
              ),
              Provide<PageCounter>(
                scope: scope1,
                builder:
                    (BuildContext context, Widget child, PageCounter counter) {
                  return Text(
                    '${counter.value}',
                    style: Theme.of(context).textTheme.display1,
                  );
                },
              ),
              Provide<PageCounter>(
                scope: scope2,
                builder:
                    (BuildContext context, Widget child, PageCounter counter) {
                  return Text(
                    '${counter.value}',
                    style: Theme.of(context).textTheme.display1,
                  );
                },
              ),
              StreamBuilder<Counter>(
                initialData: _counter,
                stream: Provide.stream<Counter>(context),
                builder:
                    (BuildContext context, AsyncSnapshot<Counter> snapshot) {
                  return Text(
                    '${snapshot.data.value}',
                    style: Theme.of(context).textTheme.display1,
                  );
                },
              ),
              FlatButton(
                child: Text("nextPage"),
                onPressed: () {
                  Navigator.push(context,
                      MaterialPageRoute(builder: (BuildContext context) {
                    return MyHomePage(
                      title: "new page",
                    );
                  }));
                },
              ),
            ],
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            _counter.inc();
            pageCounter.inc();
            pageCounter2.rec();
          },
          tooltip: 'Increment',
          child: Icon(Icons.add),
        ),
      ),
    );
  }
}

 

 

這裏定義了兩個scope,並在Provide時進行了指定

Provide<PageCounter>(
  scope: scope1,
  builder:
      (BuildContext context, Widget child, PageCounter counter) {
    return Text(
      '${counter.value}',
      style: Theme.of(context).textTheme.display1,
    );
  },
),

 

這樣只有當對應scope1的counter發出通知時,這裏纔會回調,這樣就知足了一個頁面/一個應用中有兩個相同對象的識別問題

後記

這個插件託管在google倉庫下,我的以爲應該是官方很推薦的一種狀態管理模式

相關文章
相關標籤/搜索