需要帮助了解 flutter_bloc 如何注入 bloc

Posted

技术标签:

【中文标题】需要帮助了解 flutter_bloc 如何注入 bloc【英文标题】:Need help understanding how flutter_bloc injects bloc 【发布时间】:2020-10-20 02:54:15 【问题描述】:

据我目前了解,在 runApp 方法级别提供一个 bloc 使其在所有应用程序中都可用。我错了吗?

我有这个实现

我的 main.dart 文件

void main() => runApp(
      RepositoryProvider<AuthenticationRepository>(
        create: (context) 
          return AuthenticationService();
        ,
        child: MultiBlocProvider(
          providers: [
            BlocProvider<AuthenticationBloc>(
              create: (context) 
                final authService =
                    RepositoryProvider.of<AuthenticationRepository>(context);
                return AuthenticationBloc(authService)..add(AppLoaded());
              ,
            ),
            BlocProvider<SignupBloc>(
              create: (context) 
                final authService =
                    RepositoryProvider.of<AuthenticationRepository>(context);
                return SignupBloc(authService);
              ,
            )
          ],
          child: MyApp(),
        ),
      ),
    );

class MyApp extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: BlocBuilder<AuthenticationBloc, AuthenticationState>(
        builder: (context, state) 
          if (state is AuthenticationSuccess) 
            return MainScreen(user: state.user);
          
          return LoginScreen();
        ,
      ),
    );
  

然后我有了这个小部件:

import 'dart:developer';

import 'package:myapp/features/signup/bloc/signup_bloc.dart';
import 'package:myapp/shared/ui/textStyles.dart';
import 'package:myapp/shared/ui/widgets.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:provider/provider.dart';

class ProfileInfoForm extends StatefulWidget 
  @override
  _ProfileInfoFormState createState() => _ProfileInfoFormState();


class _ProfileInfoFormState extends State<ProfileInfoForm> 
  String _firstname, _lastname, _city, _country, _gender = "";
  GlobalKey<FormState> _key = GlobalKey<FormState>();

  List<bool> _selections = List.generate(2, (index) => false);

  @override
  Widget build(BuildContext context) 
    final _signupBloc = Provider.of<SignupBloc>(context);

    return BlocListener<SignupBloc, SignupState>(
      listener: (context, state) 
        if (state is CreateAccountFailure) 
          log("message");
        
      ,
      child: BlocBuilder(
        builder: (context, state) 
          if (state is CreateAccountLoading) 
            return CircularProgressIndicator();
          
          return SingleChildScrollView(
            child: Container(
              child: Center(
                child: Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Form(
                    key: _key,
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        SizedBox(
                          height: 250,
                        ),
                        Padding(
                          padding: const EdgeInsets.all(8.0),
                          child: CustomTextField(
                            hintText: "Firstname",
                            secured: false,
                            onSave: (value) 
                              setState(() 
                                _firstname = value;
                              );
                            ,
                            onValidate: (value) 
                              if (value == "") 
                                return "Please enter your firstname";
                              
                            ,
                          ),
                        ),
                        Padding(
                          padding: const EdgeInsets.all(8.0),
                          child: CustomTextField(
                            hintText: "Lastname",
                            secured: false,
                            onSave: (value) 
                              setState(() 
                                _lastname = value;
                              );
                            ,
                            onValidate: (value) 
                              if (value == "") 
                                return "Please enter your lastname";
                              
                            ,
                          ),
                        ),
                        Padding(
                          padding: const EdgeInsets.all(8.0),
                          child: Row(
                            children: [
                              Expanded(
                                child: Text(
                                  "Select your gender",
                                  style: blackSubTitle,
                                ),
                              ),
                              ToggleButtons(
                                fillColor: Colors.white,
                                renderBorder: true,
                                color: Colors.black,
                                selectedBorderColor: Colors.redAccent,
                                borderRadius: BorderRadius.circular(20),
                                children: [
                                  Container(
                                    alignment: Alignment.center,
                                    // decoration: BoxDecoration(borderRadius: BorderRadius.circular(20)),
                                    width: ScreenUtil().setWidth(220),
                                    child: Text(
                                      "Female",
                                      style: blackSubTitle,
                                    ),
                                  ),
                                  Container(
                                    alignment: Alignment.center,
                                    width: ScreenUtil().setWidth(220),
                                    child: Text(
                                      "Male",
                                      style: blackSubTitle,
                                    ),
                                  ),
                                ],
                                isSelected: _selections,
                                onPressed: (index) 
                                  setState(() 
                                    _selections =
                                        List.generate(2, (index) => false);
                                    _selections[index] = !_selections[index];

                                    if (_selections.elementAt(0) == true) 
                                      setState(() 
                                        _gender = "Female";
                                      );
                                    
                                    if (_selections.elementAt(1) == true) 
                                      setState(() 
                                        _gender = "Male";
                                      );
                                    
                                  );
                                ,
                              )
                            ],
                          ),
                        ),
                        Padding(
                          padding: const EdgeInsets.all(8.0),
                          child: FlatButton(
                            onPressed: () 
                              if (_key.currentState.validate()) 
                                _key.currentState.save();
                                // _signupBloc.add(
                                //   InitProfilePressed(
                                //       firstname: _firstname,
                                //       lastname: _lastname,
                                //       gender: _gender),
                                // );
                               else 
                            ,
                            child: Row(
                              children: [
                                Expanded(
                                  child: Container(
                                    alignment: Alignment.center,
                                    width: 200,
                                    height: 60,
                                    decoration: BoxDecoration(
                                      borderRadius: BorderRadius.circular(30),
                                      color: Colors.black,
                                    ),
                                    child: Text(
                                      "Continue",
                                      style: whiteSubTitle,
                                    ),
                                  ),
                                ),
                              ],
                            ),
                          ),
                        )
                      ],
                    ),
                  ),
                ),
              ),
            ),
          );
        ,
      ),
    );
  

很遗憾,我收到了这个错误:

    BlocProvider.of() called with a context that does not contain a Bloc of type Bloc<dynamic, dynamic>.

    No ancestor could be found starting from the context that was passed to BlocProvider.of<Bloc<dynamic, dynamic>>().

    This can happen if the context you used comes from a widget above the BlocProvider.

    The context used was: BlocBuilder<Bloc<dynamic, dynamic>, dynamic>(dirty, state: _BlocBuilderBaseState<Bloc<dynamic, dynamic>,

动态>#a73f5(生命周期状态:创建))

BlocProvider.of>()。 如果您使用的上下文来自 BlocProvider 上方的小部件,则可能会发生这种情况。 使用的上下文是:BlocBuilder, dynamic>(dirty, state: _BlocBuilderBaseState, dynamic>#a73f5(lifecycle state: created)) 相关的导致错误的小部件是: BlocListener

#23 ComponentElement.performRebuild package:flutter/…/widgets/framework.dart:4571 #24 StatefulElement.performRebuild package:flutter/…/widgets/framework.dart:4719 #25 Element.rebuild 包:flutter/…/widgets/framework.dart:4262 #26 BuildOwner.buildScope 包:flutter/…/widgets/framework.dart:2667 #27 WidgetsBinding.drawFrame 包:flutter/…/widgets/binding.dart:866 #28 RendererBinding._handlePersistentFrameCallback 包:flutter/…/rendering/binding.dart:286 #29 SchedulerBinding._invokeFrameCallback 包:flutter/…/scheduler/binding.dart:1115 #30 SchedulerBinding.handleDrawFrame 包:flutter/…/scheduler/binding.dart:1054 #31 SchedulerBinding._handleDrawFrame 包:flutter/…/scheduler/binding.dart:970 #35 _invoke (dart:ui/hooks.dart:269:10) #36 _drawFrame (dart:ui/hooks.dart:227:3)(从 dart:async 中删除 3 帧)

我错过了什么?

谢谢你的帮助

【问题讨论】:

【参考方案1】:

除了一件事,你做的都很好

您错过了 BlocBuilder 的类型

child: BlocBuilder<SignupBloc, SignupState>(

您还可以使用 BlocConsumer,其中包括 BlocListenerBlocBuilder 功能

    return BlocConsumer<SignupBloc, SignupState>(
      listener: (context, state) 
        if (state is CreateAccountFailure) 
          log("message");
        
      ,
      builder: (context, state) 
        if (state is CreateAccountLoading) 
          return CircularProgressIndicator();
        

【讨论】:

以上是关于需要帮助了解 flutter_bloc 如何注入 bloc的主要内容,如果未能解决你的问题,请参考以下文章

如何在我的项目中应用flutter_bloc?

flutter_bloc 4.0.0如何获取事件属性参数。

SQL注入攻击的常见方式及测试方法

使用flutter_bloc提交时如何验证表单?

我需要了解如何防止 NodeJS 上的 sql 注入 sequelize ORM

如何使用flutter_bloc处理动画