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(),
)