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

5vf7fwbs  于 2023-08-07  发布在  Flutter
关注(0)|答案(3)|浏览(130)

我试图理解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()?

nr9pn0ug

nr9pn0ug1#

您可以使用提供程序包进行flutter。它有dispose的回调函数,您可以在这里处理您的块。提供程序是继承的小部件,提供了一种管理块的干净方法。顺便说一句,我只在提供程序和流中使用无状态小部件。

ar7v8xwq

ar7v8xwq2#

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

7vhp5slm

7vhp5slm3#

您可以通过在dispose方法中处理块来尝试此操作。代码实现了块模式。

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,
              ),
            ),
          ),
        );
      }
    }

字符串

相关问题