Provider
是 Flutter 中非常流行的状态管理库,它使得管理应用的状态变得简单高效。我们可以使用 Provider
来管理不同的状态,包括应用的全局状态、局部状态,甚至是依赖注入。
进阶用法
除了简单的状态共享,Provider
还可以用于一些更复杂的场景,比如多层嵌套的依赖注入 、自动销毁资源 、状态变化监听 等。接下来我将介绍一些进阶用法,帮助你更好地理解和应用 Provider
。
1. ChangeNotifier
与 Consumer
使用
最常见的 Provider
使用模式是通过 ChangeNotifier
和 Consumer
进行状态管理。在这个模式下,ChangeNotifier
充当了管理状态的角色,并在状态变化时通知界面更新。
示例:
dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => Counter(),
child: MyApp(),
),
);
}
class Counter with ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners(); // 通知消费者
}
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Provider Example')),
body: Center(
child: Consumer<Counter>(
builder: (context, counter, child) {
return Text('Counter: ${counter.count}', style: TextStyle(fontSize: 24));
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
context.read<Counter>().increment(); // 增加计数
},
child: Icon(Icons.add),
),
),
);
}
}
关键点:
ChangeNotifierProvider
:ChangeNotifierProvider
是将ChangeNotifier
放到 widget 树中的一个方式,Counter
继承了ChangeNotifier
,并且通过notifyListeners()
来通知变化。Consumer<Counter>
:Consumer
用来监听Counter
对象的变化,当状态变化时,builder
方法会被重新调用,刷新 UI。
2. 使用 Selector
优化性能
Selector
是 Provider
提供的一个优化组件,它可以帮助你精确地选择你需要的部分状态并监听变化,从而避免不必要的 UI 重建。与 Consumer
不同,Selector
只会在所选状态发生变化时重新构建 UI。
示例:
dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => Counter(),
child: MyApp(),
),
);
}
class Counter with ChangeNotifier {
int _count = 0;
int _otherValue = 0;
int get count => _count;
int get otherValue => _otherValue;
void incrementCount() {
_count++;
notifyListeners();
}
void incrementOtherValue() {
_otherValue++;
notifyListeners();
}
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Provider Selector Example')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Selector<Counter, int>(
selector: (context, counter) => counter.count, // 只选择 count 属性
builder: (context, count, child) {
return Text('Counter: $count', style: TextStyle(fontSize: 24));
},
),
Selector<Counter, int>(
selector: (context, counter) => counter.otherValue, // 只选择 otherValue 属性
builder: (context, otherValue, child) {
return Text('Other Value: $otherValue', style: TextStyle(fontSize: 24));
},
),
],
),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton(
onPressed: () {
context.read<Counter>().incrementCount(); // 增加计数
},
child: Icon(Icons.add),
),
SizedBox(height: 10),
FloatingActionButton(
onPressed: () {
context.read<Counter>().incrementOtherValue(); // 增加 otherValue
},
child: Icon(Icons.add_alert),
),
],
),
),
);
}
}
关键点:
Selector
:Selector
允许你只选择并监听状态的一部分。当count
发生变化时,只会重新构建显示count
的部分,而otherValue
的部分不会重新构建,避免不必要的 UI 更新。- 优化性能 :
Selector
是一个性能优化工具,用来减少不必要的 widget 重建。
3. 使用 Provider
实现依赖注入
Provider
不仅适用于状态管理,它还可以用来实现依赖注入(DI)。通过 Provider
,你可以在应用中创建并注入单例或多个不同类型的对象,使得它们在整个应用中共享。
示例:
dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(
MultiProvider(
providers: [
Provider(create: (context) => ApiService()),
Provider(create: (context) => UserService(context.read<ApiService>())),
],
child: MyApp(),
),
);
}
class ApiService {
String fetchData() {
return "Data from API";
}
}
class UserService {
final ApiService apiService;
UserService(this.apiService);
String getUserData() {
return apiService.fetchData();
}
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Provider Dependency Injection')),
body: Center(
child: Consumer<UserService>(
builder: (context, userService, child) {
return Text(userService.getUserData(), style: TextStyle(fontSize: 24));
},
),
),
),
);
}
}
关键点:
MultiProvider
:当你需要提供多个依赖项时,可以使用MultiProvider
。这里我们注入了两个服务:ApiService
和UserService
。- 依赖注入 :
UserService
依赖于ApiService
,并且通过context.read<ApiService>()
获取该服务。
4. 使用 FutureProvider
和 StreamProvider
Provider
支持 Future
和 Stream
,你可以使用 FutureProvider
来异步加载数据,或使用 StreamProvider
来监听数据流。这对于异步操作(如网络请求或数据库查询)非常有用。
示例:使用 FutureProvider
dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => DataProvider(),
child: MyApp(),
),
);
}
class DataProvider with ChangeNotifier {
Future<String> fetchData() async {
await Future.delayed(Duration(seconds: 2));
return "Hello from the Future!";
}
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('FutureProvider Example')),
body: Center(
child: Consumer<DataProvider>(
builder: (context, dataProvider, child) {
return FutureProvider<String>(
create: (_) => dataProvider.fetchData(),
initialData: "Loading...",
child: Builder(
builder: (context) {
String data = context.watch<String>();
return Text(data, style: TextStyle(fontSize: 24));
},
),
);
},
),
),
),
);
}
}
关键点:
FutureProvider
:FutureProvider
用来管理和提供一个异步操作(Future
)的结果。你可以用它来在获取数据时显示加载状态。- 异步数据更新 :
FutureProvider
会自动处理Future
状态,提供初始数据并在数据加载完成后更新。
5. Provider
和 ChangeNotifier
自动销毁资源
使用 ChangeNotifierProvider
时,可以确保在 Provider
不再使用时自动销毁其资源。通过设置 dispose
方法,可以确保当 Provider
不再被使用时自动清理资源,避免内存泄漏。
dart
ChangeNotifierProvider(
create: (context) => MyNotifier(),
dispose: (context, notifier) => notifier.dispose(),
)