如何在使用 BLoC 模式和 StatelessWidget 时调用 dispose



我试图理解 BLoC 模式,但我无法弄清楚在我的示例中何时何地调用 dispose()。

我正在尝试了解 Flutter 中的各种状态管理技术。

我想出了一个我设法使用 StatefulWidget、scoped_model 和 streams 构建的示例。

我相信我终于想出了如何让我的示例使用"BloC"模式,但我在调用 dispose() 方法时遇到了问题,因为我只使用 StatelessWidgets。

我尝试将PageOne和PageTwo转换为StatefulWidget并调用dispose(),但最终在页面之间移动时过早关闭流。

在我的示例中,我是否根本不应该担心手动关闭流?

import 'package:flutter/material.dart';
import 'dart:async';
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StreamBuilder<ThemeData>(
initialData: bloc.themeProvider.getThemeData,
stream: bloc.streamThemeDataValue,
builder: (BuildContext context, AsyncSnapshot<ThemeData> snapshot) {
return MaterialApp(
title: 'bloc pattern example',
theme: snapshot.data,
home: BlocPatternPageOne(),
);
},
);
}
}
// -- page_one.dart
class BlocPatternPageOne extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('(block pattern) page one'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
buildRaisedButton(context),
buildSwitchStreamBuilder(),
],
),
),
);
}
StreamBuilder<bool> buildSwitchStreamBuilder() {
return StreamBuilder<bool>(
initialData: bloc.switchProvider.getSwitchValue,
stream: bloc.streamSwitchValue,
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
return Switch(
value: snapshot.data,
onChanged: (value) {
bloc.sinkSwitchValue(value);
},
);
},
);
}
Widget buildRaisedButton(BuildContext context) {
return RaisedButton(
child: Text('go to page two'),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return BlocPatternPageTwo();
},
),
);
},
);
}
}
// -- page_two.dart
class BlocPatternPageTwo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('(bloc pattern) page two'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
buildRaisedButton(context),
buildSwitchStreamBuilder(),
],
),
),
);
}
StreamBuilder<bool> buildSwitchStreamBuilder() {
return StreamBuilder<bool>(
initialData: bloc.switchProvider.getSwitchValue,
stream: bloc.streamSwitchValue,
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
return Switch(
value: snapshot.data,
onChanged: (value) {
bloc.sinkSwitchValue(value);
},
);
},
);
}
Widget buildRaisedButton(BuildContext context) {
return RaisedButton(
child: Text('go back to page one'),
onPressed: () {
Navigator.of(context).pop();
},
);
}
}
// -- bloc.dart
class SwitchProvider {
bool _switchValue = false;
bool get getSwitchValue => _switchValue;
void updateSwitchValue(bool value) {
_switchValue = value;
}
}
class ThemeProvider {
ThemeData _themeData = ThemeData.light();
ThemeData get getThemeData => _themeData;
void updateThemeData(bool value) {
if (value) {
_themeData = ThemeData.dark();
} else {
_themeData = ThemeData.light();
}
}
}
class Bloc {
final StreamController<bool> switchStreamController =
StreamController.broadcast();
final SwitchProvider switchProvider = SwitchProvider();
final StreamController<ThemeData> themeDataStreamController =
StreamController();
final ThemeProvider themeProvider = ThemeProvider();
Stream get streamSwitchValue => switchStreamController.stream;
Stream get streamThemeDataValue => themeDataStreamController.stream;
void sinkSwitchValue(bool value) {
switchProvider.updateSwitchValue(value);
themeProvider.updateThemeData(value);
switchStreamController.sink.add(switchProvider.getSwitchValue);
themeDataStreamController.sink.add(themeProvider.getThemeData);
}
void dispose() {
switchStreamController.close();
themeDataStreamController.close();
}
}
final bloc = Bloc();

目前一切正常,但是,我想知道我是否应该担心手动关闭流或让 Flutter 自动处理它。

如果我应该手动关闭它们,你什么时候在我的例子中调用 dispose()?

您可以使用提供程序包进行颤振。它具有用于处置的回调,您可以在其中处置您的集团。提供程序是继承的小部件,提供了一种管理块的干净方法。顺便说一句,我只对提供程序和流使用无状态小部件。

在无状态小部件中,没有 dispose 方法,因此您无需担心在哪里调用它。 就这么简单

您可以通过在处置方法中释放 bloc 来尝试此操作。代码实现集团模式。

import 'package:flutter/material.dart';
@RoutePage()
class CartView extends StatefulWidget {
const CartView({super.key});

@override
State<CartView> createState() => _CartViewState();
}

class _CartViewState extends State<CartView> {
final cartBloc = CartBloc();

@override
void initState() {
super.initState();
cartBloc.add(CartInitialEvent());
}

@override
void dispose() {
super.dispose();
cartBloc.close();
}

@override
Widget build(BuildContext context) {
return BlocConsumer<CartBloc, CartState>(
bloc: cartBloc,
listenWhen: (previous, current) => current is CartActionState,
listener: (context, state) {
if (state is CartErrorState) {
context.router.pop();
Utilities.flushBarErrorMessage("Couldn't delete from cart", context);
}
},
buildWhen: (previous, current) => current is! CartActionState,
builder: (context, state) {
switch (state.runtimeType) {
case CartLoadingState:
return const LoadingWidget();
case CartSuccessLoadedState:
final cartLoadedState = state as CartSuccessLoadedState;
final localOrderCartItems =
cartLoadedState.localOrderCartModel!.data;
return BuildLocalShopLoadedView(
cartItems: localOrderCartItems![0].cartItems!,
cartBloc: cartBloc,
cartTotal:
cartLoadedState.localOrderCartModel!.data![0].cartTotal,
coId: cartLoadedState.localOrderCartModel!.data![0].coId!,
);
case CartEmptyLoadedState:
return Scaffold(
// backgroundColor: Colors.g,
appBar: const CustomAppBar(
appBarTitle: "My Cart",
),
body: Padding(
padding: AppPadding.kQuatHalfPad,
child: Column(
children: [
LottieBuilder.asset(
'assets/lottie/empty-cart-animation.json'),
SizedBox(height: 20.h),
const AppSmallText(
text: 'Your Cart is Empty',
fontSize: 23,
),
SizedBox(height: 10.h),
const AppSmallText(
text:
"Looks like you haven't added anything to your cart yet",
fontWeight: FontWeight.normal,
),
SizedBox(height: 10.h),
PrimaryActionButton(
labelText: 'Start shopping',
onPressed: () {
context.router.popUntilRouteWithName(RoutesName.localShop);

context.router
.popUntilRouteWithName(LocalShopViewRoute.name);

},
),
],
),
),
);
default:
return const SizedBox();
}
},
);
}
}

class BuildLocalShopLoadedView extends StatefulWidget {
final List<CartItem>? cartItems;
final int? cartTotal;
final String coId;
final CartBloc cartBloc;

const BuildLocalShopLoadedView({
Key? key,
required this.cartItems,
required this.cartBloc,
this.cartTotal = 0,
required this.coId,
}) : super(key: key);

@override
State<BuildLocalShopLoadedView> createState() =>
_BuildLocalShopLoadedViewState();
}

class _BuildLocalShopLoadedViewState extends State<BuildLocalShopLoadedView> {
// final _razorpay = Razorpay();
String currency = '₹';

// final RazorPayIntegration _integration = RazorPayIntegration();

@override
void initState() {
super.initState();
// _integration.intiateRazorPay();
}

@override
void dispose() {
// TODO: implement dispose
super.dispose();
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const CustomAppBar(
appBarTitle: "My Cart",
),
bottomNavigationBar: Padding(
padding: AppPadding.kSinglePad,
child: Container(
height: 90.h,
padding: AppPadding.kHalfPad,
decoration: BoxDecoration(
color: AppColors.kBottomSheetLightButtonColor,
borderRadius: AppBorder.kHalfCurve,
),
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const AppSmallText(
text: 'Total price',
color: AppColors.kDeepAvatarColor,
),
AppSmallText(
text: '$currency${widget.cartTotal}',
color: AppColors.kDeepAvatarColor,
fontSize: 30,
),
],
),
SizedBox(
width: 10.w,
),
Expanded(
child: ElevatedButton(
onPressed: () {
//! navigate to checkout view
context.navigateTo(const CheckoutViewRoute());
},
style: ElevatedButton.styleFrom(
elevation: 0.0,
shape: RoundedRectangleBorder(
borderRadius: AppBorder.kHalfCurve,
),
backgroundColor: AppColors.kPrimaryButtonColor,
minimumSize: const Size(double.maxFinite, double.maxFinite),
),
child: const AppSmallText(
text: 'CHECKOUT',
letterSpacing: 1,
fontWeight: FontWeight.w800,
),
),
),
],
),
),
),
body: SafeArea(
child: Padding(
padding: AppPadding.kHalfHorizontal,
child: CartListViewBuilder(
cartBloc: widget.cartBloc,
cartItems: widget.cartItems,
),
),
),
);
}
}

最新更新