Flutter Provider 之 FutureProvider 與 StreamProvider

Provider 基本使用

在以前的一篇文章中,介紹了 Provider 的基本使用,總結一下,Provider 的基本使用總結以下 :git

  1. 定義數據 model 管理變量
  2. 經過 ChangeNotifierProvider 將狀態和須要使用的狀態的組件組合到一塊兒
  3. 使用 Provider.of 或者 Consumer 監聽狀態或者改變狀態。

固然若是是在一個 widget 或者頁面裏面須要使用多個狀態, ChangeNotifierProvider 顯然是不夠的,所以 Provider 提供了 MultiProvider 來使用多個狀態,像這樣github

MultiProvider(
        providers: [
          ChangeNotifierProvider(builder: (_) => BasicCounter(0)),
          FutureProvider(builder: (_) => UserProvider().loadUserData()),
          StreamProvider(builder: (_) => EventProvider().intStream(), initialData:ThemeData.light() )
        ],
        child: MyApp()
    )
複製代碼

就可使用多個狀態了。web

接下來介紹 Provider 裏面另外兩個比較重要的 Provider: FutureProvider 和 StreamProvider。 經過名字就看得出來,這兩個 Provider 和異步執行有關。更詳細的介紹和使用參考這篇文章,若是你不能訪問這篇文章也沒有關係,接下來我會根據這篇文章來介紹一下這兩個 Provider 是若是使用的。編程

FutureProvider 的使用

FutureProvider 使用起來也很簡單。先看一下構造函數:json

FutureProvider({
    Key key,
    @required ValueBuilder<Future<T>> builder,
    T initialData,
    ErrorBuilder<T> catchError,
    UpdateShouldNotify<T> updateShouldNotify,
    Widget child,
  }) : this._(
          key: key,
          initialData: initialData,
          catchError: catchError,
          updateShouldNotify: updateShouldNotify,
          delegate: BuilderStateDelegate(builder),
          child: child,
        );

複製代碼

能夠看到,builder 的返回值類型確實是 Future 類型的,而且能夠經過 initiaData 指定初始值。接下來具體看一下如何使用。bash

一、定義 異步操做,返回值類型須要是 Future 類型的

好比讀取 assets 下的 json 文件並解析,這確定是一個耗時的操做,所以須要異步進行。微信

class UserProvider {
  final String _dataPath = "assets/data/users.json";
  List<User> users;

  Future<List<User>> loadUserData( ) async {
    var dataString = await loadAsset();
    Map<String, dynamic> jsonUserData = jsonDecode(dataString);
    users = UserList.fromJson(jsonUserData['users']).users;
    print('done loading user!' + jsonEncode(users));
    return users;
  }

  Future<String> loadAsset() async {
    return await Future.delayed(Duration(seconds: 10), () async {
      return await rootBundle.loadString('assets/data/users.json');
    });
  }
}
複製代碼

二、FutureProvider 中指定剛纔定義的 UserProvider 而且調用初始化函數。

MultiProvider(
        providers: [
          ChangeNotifierProvider(builder: (_) => BasicCounter(0)),
          FutureProvider(builder: (_) => UserProvider().loadUserData()),
          StreamProvider(builder: (_) => EventProvider().intStream(), initialData: 0)
        ],
        child: MyApp()
    )
複製代碼

三、使用 Provider.of 獲取狀態

var _users = Provider.of<List<User>>(context);
複製代碼

接下來就能夠經過 users 正常的使用變量了。app

ListView.builder(
                itemCount: _users.length,
                itemBuilder: (context, index){
                  return Container(
                      height: 50,
                      color: Colors.grey[(index*200) % 400],
                      child: Center(
                          child: Text(
                              '${_users[index].firstName} ${_users[index].lastName} | ${_users[index].website}'
                          )
                      )
                  );
                }
            )
複製代碼

StreamProvider 的使用

其構造函數以下:異步

StreamProvider({
    Key key,
    @required ValueBuilder<Stream<T>> builder,
    T initialData,
    ErrorBuilder<T> catchError,
    UpdateShouldNotify<T> updateShouldNotify,
    Widget child,
  }) : this._(
          key: key,
          delegate: BuilderStateDelegate<Stream<T>>(builder),
          initialData: initialData,
          catchError: catchError,
          updateShouldNotify: updateShouldNotify,
          child: child,
        );

複製代碼

和 FuturePrivider 相似,返回值是 Stream 類型的,也能夠指定初始值。接下來看如何使用。async

一、定義能夠返回 Stream 類型的操做

這裏只是每隔兩秒返回一個數字。

class EventProvider {

  Stream<int> intStream() {
    Duration interval = Duration(seconds: 2);
   return Stream<int>.periodic(interval, (int _count) => _count++);

  }

}
複製代碼

二、初始化 StreamBuilder 並啓動發送 Stream 的操做

MultiProvider(
        providers: [
          ChangeNotifierProvider(builder: (_) => BasicCounter(0)),
          FutureProvider(builder: (_) => UserProvider().loadUserData()),
          StreamProvider(builder: (_) => EventProvider().intStream(), initialData:0)
        ],
        child: MyApp()
    )
複製代碼

三、經過 Provider.of 讀取狀態

var _value = Provider.of<ThemeData>(context);
複製代碼

使用這個狀態:

Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text('StreamProvider Example'),
                SizedBox(height: 150),
                Text('${_value.toString()}',
                    style: Theme.of(context).textTheme.display1
                )
              ],
            )
        )
複製代碼

這樣界面上的數字就是每隔兩秒鐘刷新一次了。

接下來再看一個例子,經過 StreamProvider 來改變主題。 將剛纔的 EventProvider 改成以下:

class EventProvider {

  Stream<ThemeData> intStream() {
    Duration interval = Duration(seconds: 2);
   // ThemeData  themeData = _themeData == ThemeData.light()?ThemeData.dark():ThemeData.light()
    return Stream<ThemeData>.periodic(interval, (int _count) => _count %2 == 0?ThemeData.light():ThemeData.dark() );
   //return Stream<int>.periodic(interval, (int _count) => _count %2 == 0? 11: 22  );
  // return Stream<int>.periodic(interval, (int _count) => _count++);
  }

}
複製代碼

每隔兩秒改變一次主題。

初始化 StreamProvider:

MultiProvider(
        providers: [
          ChangeNotifierProvider(builder: (_) => BasicCounter(0)),
          FutureProvider(builder: (_) => UserProvider().loadUserData()),
          StreamProvider(builder: (_) => EventProvider().intStream(), initialData:ThemeData.light())
        ],
        child: MyApp()
    )
複製代碼

使用 Provider.of 讀取狀態

return MaterialApp(
        title: 'Flutter Demo',
       // theme: ThemeData.light(),
      //  theme: themeData,
        theme:  Provider.of<ThemeData>(context),


        home:  DefaultTabController(
            length: 3,
            child: DefaultTabController(
              length: 3,
              child: Scaffold(
                appBar: AppBar(
                  title: Text("Provider Demo:" ),
                  bottom: TabBar(
                    tabs: [
                      Tab(icon: Icon(Icons.add)),
                      Tab(icon: Icon(Icons.person)),
                      Tab(icon: Icon(Icons.message)),
                    ],
                  ),
                ),
                body: TabBarView(
                  children: [
                    HomePage(),
                    MyUserPage(),
                    MyEventPage(),
                  ],
                ),
              ),
            )
        )

    );
複製代碼

效果以下:

github

最後

歡迎關注「Flutter 編程開發」微信公衆號 。

相關文章
相關標籤/搜索