在以前的一篇文章中,介紹了 Provider 的基本使用,總結一下,Provider 的基本使用總結以下 :git
固然若是是在一個 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 使用起來也很簡單。先看一下構造函數: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
好比讀取 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');
});
}
}
複製代碼
MultiProvider(
providers: [
ChangeNotifierProvider(builder: (_) => BasicCounter(0)),
FutureProvider(builder: (_) => UserProvider().loadUserData()),
StreamProvider(builder: (_) => EventProvider().intStream(), initialData: 0)
],
child: MyApp()
)
複製代碼
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({
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
這裏只是每隔兩秒返回一個數字。
class EventProvider {
Stream<int> intStream() {
Duration interval = Duration(seconds: 2);
return Stream<int>.periodic(interval, (int _count) => _count++);
}
}
複製代碼
MultiProvider(
providers: [
ChangeNotifierProvider(builder: (_) => BasicCounter(0)),
FutureProvider(builder: (_) => UserProvider().loadUserData()),
StreamProvider(builder: (_) => EventProvider().intStream(), initialData:0)
],
child: MyApp()
)
複製代碼
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(),
],
),
),
)
)
);
複製代碼
效果以下:
歡迎關注「Flutter 編程開發」微信公衆號 。