Flutter响应式编程插件inherited_rxdart的使用
Flutter响应式编程插件inherited_rxdart的使用
特性
inherited_rxdart
是一个简单的状态管理解决方案,它结合了继承小部件(Inherited Widget)和RxDart的功能。通过使用多个Bloc(业务逻辑组件),你可以为你的应用程序创建状态管理逻辑,这些Bloc本质上只是流和RxDart。
入门
首先,导入 inherited_rxdart
包:
import 'package:inherited_rxdart/inherited_rxdart.dart';
接下来,定义你的状态类和Bloc:
[@immutable](/user/immutable)
class MyState {
final int number;
final String text;
const MyState({required this.number, required this.text});
MyState copyWith({int? number, String? text}) {
return MyState(number: number ?? this.number, text: text ?? this.text);
}
}
class CounterBloc extends RxBloc<MyState, String> {
CounterBloc(MyState initialState) : super(initialState);
void showDialog() {
notify("showDialog");
}
void changeText(String newText) {
state = state.copyWith(text: newText);
}
void increase() {
state = state.copyWith(number: state.number + 1);
}
void decrease() {
state = state.copyWith(number: state.number - 1);
}
}
然后,在你的应用中使用它们:
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: RxProvider<CounterBloc>(
create: () => CounterBloc(const MyState(text: "hi", number: 0)),
child: MyHomePage(),
)
);
}
}
在子树中的任何地方访问它们:
final bloc = RxProvider.of<CounterBloc>(context);
使用
查看每个API的文档以获取更多详细信息。该库支持Bloc模式和ViewModel模式来管理你的应用程序状态。
Bloc的小部件
对于Bloc,有一些特定的小部件用于不同的目的,包括重建和监听等:
RxBuilder
: 根据状态构建小部件。RxListener
: 监听状态变化和通知。RxStateListener
: 只监听状态变化。RxConsumer
: 结合了RxListener
和RxBuilder
。RxStateConsumer
: 结合了RxStateListener
和RxBuilder
。RxSelector
: 根据状态的特定属性选择性地重建小部件。
RxCubit
RxCubit
是一个简单的小部件,它在整个生命周期中发出状态,并在必要时重建小部件。它与以下小部件一起工作:
RxBuilder
RxSelector
RxStateConsumer
RxStateListener
RxBloc
RxBloc
是一个带有通知的状态小部件,可以被监听并相应地作出反应。它与以下小部件一起工作:
RxBuilder
RxListener
RxStateListener
RxConsumer
RxStateConsumer
RxSelector
RxViewModel
RxViewModel
是一种基于简单视图模型的状态管理方式,附带了相关的构建器:
RxViewModelBuilder
: 处理状态发出时重建小部件。RxViewModelSelector
: 当状态改变时选择性地重建。RxViewModelListener
: 状态改变时的监听回调。RxViewModelConsumer
: 结合了构建器和监听器。
RxValue
RxValue
是一种用于响应式状态管理的值,当其值设置时,将导致其依赖项重建。
RxValueBuilder
: 与RxValue
一起使用。
ServiceProvider
还有一个简单的服务提供商,用于仓库或简单地通过小部件子树注入实例。
ServiceProvider
注册全局单例
尽管不完全是继承,但此库确实提供了通过GetIt注册实例的方法,并在构建器和监听器中使用它们。此功能可以通过 RxProvider
的静态方法访问。
EventDispatcherMixin
这是一个混入,用于向 RxCubit
/RxBloc
添加事件分发能力,并注册对这些事件的回调。
默认情况下,RxCubit
/RxBloc
有一个流,即 RxBase.stateStream
,该流将状态输出到UI以重建UI。
这个混入引入了另一个从UI到 RxCubit
/RxBloc
的流,可用于处理事件类型及其子类型。每个都可以使用 StreamTransformer
进行转换。
额外信息
为了提供多个Bloc/视图模型/服务实例,鼓励使用以下小部件:
RxMultiProvider
MultiServiceProvider
为了快速访问Bloc/服务,而不是使用这些函数:
RxProvider.of<MyBloc>(context);
ServiceProvider.of<MyService>(context);
可以使用:
context.watch<MyBloc>(); // 获取Bloc/视图模型的实例并订阅其更改。
context.read<MyBloc>(); // 获取Bloc/视图模型的实例。
context.get<MyService>(); // 获取服务的实例。
并且:
final text = RxValue<String>("hello");
等价于:
final text = "hello".rx;
完整示例代码
import 'package:flutter/material.dart';
import 'package:inherited_rxdart/inherited_rxdart.dart';
void main() => runApp(const App());
[@immutable](/user/immutable)
class MyState {
final int number;
final String text;
const MyState({required this.number, required this.text});
MyState copyWith({int? number, String? text}) {
return MyState(number: number ?? this.number, text: text ?? this.text);
}
}
class CounterBloc extends RxBloc<MyState, String> {
CounterBloc(MyState initialState) : super(initialState);
void showDialog() {
notify("showDialog");
}
void changeText(String newText) {
state = state.copyWith(text: newText);
}
void increase() {
state = state.copyWith(number: state.number + 1);
}
void decrease() {
state = state.copyWith(number: state.number - 1);
}
}
class CounterBloc2 extends RxCubit<int> {
CounterBloc2(int initialState) : super(initialState);
void increase() {
state++;
}
void decrease() {
state--;
}
}
class CounterViewModel extends RxViewModel {
int num1;
int num2;
final num3 = 0.rx;
CounterViewModel(this.num1, [this.num2 = 0]);
void increaseNum3() {
num3.value++;
}
void increase() {
num1++;
num2++;
stateChanged();
}
void decrease() {
num1--;
// num2--;
stateChanged();
}
}
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: RxMultiProvider(
providers: [
RxProvider<CounterBloc>(
create: () => CounterBloc(const MyState(text: "hi", number: 0))),
RxProvider<CounterBloc2>(create: () => CounterBloc2(10)),
RxProvider<CounterViewModel>(
create: () => CounterViewModel(20),
),
],
child: const MyHomePage(),
),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({Key? key}) : super(key: key);
[@override](/user/override)
Widget build(BuildContext context) {
debugPrint("build MyHomePage");
return Scaffold(
appBar: AppBar(),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const MyCounter(),
RxSelector<CounterBloc, MyState, String>(
stateRebuildSelector: (state) {
return state.text;
}, builder: (context, value) {
debugPrint("build Text");
return Text("state text: $value");
}),
RxViewModelSelector<CounterViewModel, int>(
stateRebuildSelector: (state) {
return state.num2;
}, builder: (context, value) {
debugPrint("build num2");
return Text("state num2: $value");
}),
TextField(
onSubmitted: (value) {
RxProvider.of<CounterBloc>(context, listen: false)
.changeText(value);
},
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
ElevatedButton(
onPressed: () {
RxProvider.of<CounterBloc>(context, listen: false)
.increase();
RxProvider.of<CounterBloc2>(context, listen: false)
.increase();
RxProvider.of<CounterViewModel>(context, listen: false)
.increase();
},
child: const Text("Increase")),
ElevatedButton(
onPressed: () {
RxProvider.of<CounterBloc>(context, listen: false)
.decrease();
RxProvider.of<CounterBloc2>(context, listen: false)
.decrease();
RxProvider.of<CounterViewModel>(context, listen: false)
.decrease();
},
child: const Text("Decrease")),
],
),
ElevatedButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(builder: (_) {
return RxProvider.value(
value:
RxProvider.of<CounterBloc>(context, listen: false),
child: const MyNested());
}));
},
child: const Text("New Screen")),
],
),
),
);
}
}
class MyCounter extends StatelessWidget {
const MyCounter({Key? key}) : super(key: key);
[@override](/user/override)
Widget build(BuildContext context) {
debugPrint("build MyCounter");
return RxListener<CounterBloc, MyState, String>(
stateCallback: (context, state) {
debugPrint(
"from RxBlocListener: CounterBloc/${state.number}/${state.text}");
},
child: RxStateListener<CounterBloc2, int>(
stateCallback: (context, state) {
debugPrint("from RxStateListener: CounterBloc2/$state");
},
child: RxStateListener<CounterBloc, MyState>(
stateCallback: (context, state) {
debugPrint(
"from RxStateListener: CounterBloc/${state.number}/${state.text}");
},
child: RxViewModelListener<CounterViewModel>(
stateCallback: (context, state) {
debugPrint(
"from RxStateListener: CounterBloc3/${state.num1}/${state.num2}");
},
child: Column(
children: [
RxBuilder<CounterBloc, MyState>(
builder: (context, state) {
debugPrint("build Number 1");
return Text('counter bloc 1: ${state.number}');
},
shouldRebuildWidget: (prev, curr) {
return prev.number != curr.number;
},
),
RxBuilder<CounterBloc2, int>(
builder: (context, state) {
debugPrint("build Number 2");
return Text('counter bloc 2: $state');
},
shouldRebuildWidget: (prev, curr) {
return curr < 10;
},
),
RxViewModelBuilder<CounterViewModel>(
builder: (context, state) {
debugPrint("build Number 3");
return Text('counter bloc 3: ${state.num1}');
},
shouldRebuildWidget: (state) {
return state.num1 < 20;
},
),
RxValueBuilder<int>(
value: context.read<CounterViewModel>().num3,
builder: (context, value) {
debugPrint(
"rebuild elevated button of counter view model");
return ElevatedButton(
onPressed: () {
context.read<CounterViewModel>().increaseNum3();
},
child: Text("Num3: $value"));
}),
],
),
),
),
),
);
}
}
class MyNested extends StatelessWidget {
const MyNested({Key? key}) : super(key: key);
[@override](/user/override)
Widget build(BuildContext context) {
debugPrint("build MyNested");
return RxListener<CounterBloc, MyState, String>(
notificationCallback: (context, notification) {
if (notification == "showDialog") {
showDialog(
context: context,
builder: (context) {
return const Dialog(
child: Text("This is a dialog"),
);
});
}
},
stateCallback: (context, state) {
debugPrint("this is stateCallback");
},
child: Scaffold(
appBar: AppBar(),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
RxBuilder<CounterBloc, MyState>(builder: (context, state) {
debugPrint("build BlocBuilder 2 ");
return Text(state.number.toString());
}),
ElevatedButton(
onPressed: () {
RxProvider.of<CounterBloc>(context, listen: false)
.showDialog();
},
child: const Text("show notification")),
],
),
),
),
);
}
}
更多关于Flutter响应式编程插件inherited_rxdart的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter响应式编程插件inherited_rxdart的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
在Flutter中进行响应式编程时,inherited_rxdart
是一个非常有用的插件,它结合了 InheritedWidget
和 rxdart
库,以提供响应式数据管理能力。rxdart
是一个基于 Dart 的响应式扩展库,主要用于处理 Dart Streams。结合 InheritedWidget
,inherited_rxdart
可以让我们在 Flutter 应用中高效地管理状态,并在状态变化时通知相关的监听器。
以下是一个使用 inherited_rxdart
的简单示例,展示如何创建一个响应式的数据提供者,并在数据变化时通知子组件。
1. 添加依赖
首先,在你的 pubspec.yaml
文件中添加 inherited_rxdart
和 rxdart
依赖:
dependencies:
flutter:
sdk: flutter
inherited_rxdart: ^x.y.z # 请替换为最新版本号
rxdart: ^x.y.z # 请替换为最新版本号
然后运行 flutter pub get
。
2. 创建响应式数据提供者
创建一个继承自 InheritedRxDartObject
的类,用于提供响应式数据。这里我们假设有一个简单的计数器示例。
import 'package:flutter/material.dart';
import 'package:inherited_rxdart/inherited_rxdart.dart';
import 'package:rxdart/rxdart.dart';
class CounterProvider extends InheritedRxDartObject<int> {
CounterProvider({
required Widget child,
required ValueStream<int> counterStream,
}) : super(child: child, stream: counterStream);
// 获取 CounterProvider 的静态方法
static CounterProvider of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<CounterProvider>()!;
}
// 更新计数器的值
void increment() {
// 假设你有一个 BehaviorSubject 来管理计数器状态
final subject = (stream as BehaviorSubject<int>);
subject.add(subject.value! + 1);
}
}
3. 创建计数器逻辑
接下来,我们创建一个包含计数器逻辑的 Widget,并使用 CounterProvider
来提供数据。
import 'package:flutter/material.dart';
import 'package:rxdart/rxdart.dart';
class CounterApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
final counterController = BehaviorSubject<int>.seeded(0);
return CounterProvider(
counterStream: counterController.stream,
child: MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Inherited RxDart Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
StreamBuilder<int>(
stream: counterController.stream,
builder: (context, snapshot) {
return Text(
'${snapshot.data ?? 0}',
style: Theme.of(context).textTheme.headline4,
);
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// 使用 CounterProvider 的 of 方法获取实例并调用 increment
CounterProvider.of(context).increment();
},
tooltip: 'Increment',
child: Icon(Icons.add),
),
),
),
);
}
@override
void dispose() {
// 清理资源
counterController.close();
super.dispose();
}
}
4. 运行应用
将 CounterApp
作为应用的根 Widget:
void main() {
runApp(CounterApp());
}
总结
以上代码展示了如何使用 inherited_rxdart
插件结合 rxdart
实现响应式编程。CounterProvider
使用 InheritedRxDartObject
来提供响应式数据,并在数据变化时通知子组件。StreamBuilder
用于监听数据变化并更新 UI。通过这种方式,我们可以轻松地在 Flutter 应用中实现状态管理。