【问题标题】:Unhandled Exception: NoSuchMethodError: The method 'close' was called on null. Flutter BLoC未处理的异常:NoSuchMethodError:在 null 上调用了方法“close”。颤振块
【发布时间】:2021-06-08 21:14:11
【问题描述】:

我正在尝试“关闭” BLoC 状态。我基本上是在尝试处置状态。

这是我的应用的外观。

当我单击“添加”文本按钮时,它会显示一个警告对话框,提示必须填写表单才能继续。当我填写表格时,它会生成一个代码,它就像一个魅力。即使调试控制台向我显示它尝试调用“关闭”方法的错误,但没有这样的方法。任何想法如何解决它?

代码:

import 'dart:io';

import 'package:duckie/blocs/manual_input/manual_input_bloc.dart';
import 'package:duckie/screens/widgets/alert_dialog.dart';
import 'package:duckie/screens/widgets/custom_text_field.dart';
import 'package:duckie/shared/text_styles.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

class ManualInputScreen extends StatefulWidget {
  @override
  _ManualInputScreenState createState() => _ManualInputScreenState();
}

class _ManualInputScreenState extends State<ManualInputScreen> {
  String secretKey;
  String issuer;
  String accountName;
  String numberOfDigits = '6';
  String timeStep = '30';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(
          'manual-input',
          style: TextStyles.appBarText,
        ).tr(),
        centerTitle: true,
        elevation: 0.0,
        actions: [
          BlocConsumer<ManualInputBloc, ManualInputState>(
            listener: (context, state) {
              if (state is ManualInputError) {
                Platform.isAndroid
                    ? CustomAlertDialog.showAndroidAlertDialog(
                        context,
                        state.alertDialogErrorTitle,
                        state.alertDialogErrorContent)
                    : CustomAlertDialog.showIosAlertDialog(
                        context,
                        state.alertDialogErrorTitle,
                        state.alertDialogErrorContent);
              }
              ManualInputBloc manualInputBloc;
              manualInputBloc.close();
            },
            builder: (context, state) {
              if (state is ManualInputInitial || state is ManualInputFinal) {
                return TextButton(
                  onPressed: () {
                    BlocProvider.of<ManualInputBloc>(context).add(
                        GetFormTextEvent(secretKey, issuer, accountName,
                            numberOfDigits, timeStep));
                  },
                  child: Text('add').tr(),
                );
              }
              return TextButton(
                onPressed: () {},
                child: Text('add').tr(),
              );
            },
          )
        ],
      ),
      body: Container(
        padding: EdgeInsets.all(8.0),
        child: ListView(
          children: [
            CustomTextField(
              labelText: 'secret-key'.tr(),
              onChanged: (value) {
                setState(() {
                  secretKey = value;
                });
              },
            ),
            SizedBox(
              height: 8.0,
            ),
            CustomTextField(
              labelText: 'issuer'.tr(),
              onChanged: (value) {
                issuer = value;
              },
            ),
            SizedBox(
              height: 8.0,
            ),
            CustomTextField(
              labelText: 'account-name'.tr(),
              onChanged: (value) {
                setState(() {
                  accountName = value;
                });
              },
            ),
            SizedBox(
              height: 8.0,
            ),
            Platform.isAndroid
                ? ListBody(
                    children: [
                      Text('number-of-digits').tr(),
                      SizedBox(
                        height: 5.0,
                      ),
                      DropdownButton(
                        value: numberOfDigits,
                        onChanged: (value) {
                          setState(() {
                            numberOfDigits = value;
                          });
                        },
                        items: [
                          DropdownMenuItem(
                            value: '6',
                            child: Text('6'),
                          ),
                          DropdownMenuItem(
                            value: '8',
                            child: Text('8'),
                          ),
                        ],
                      )
                    ],
                  )
                : ListBody(
                    children: [
                      Text('number-of-digits').tr(),
                      SizedBox(
                        height: 5.0,
                      ),
                      CupertinoSegmentedControl(
                        groupValue: numberOfDigits,
                        children: {
                          '6': Text('6'),
                          '8': Text('8'),
                        },
                        onValueChanged: (value) {
                          setState(() {
                            numberOfDigits = value;
                          });
                        },
                      ),
                    ],
                  ),
            SizedBox(
              height: 8.0,
            ),
            Platform.isAndroid
                ? ListBody(
                    children: [
                      Text('time-step').tr(),
                      SizedBox(
                        height: 5.0,
                      ),
                      DropdownButton(
                        value: timeStep,
                        onChanged: (value) {
                          setState(() {
                            timeStep = value;
                          });
                        },
                        items: [
                          DropdownMenuItem(
                            value: '30',
                            child: Text('30'),
                          ),
                          DropdownMenuItem(
                            value: '60',
                            child: Text('60'),
                          ),
                        ],
                      )
                    ],
                  )
                : ListBody(
                    children: [
                      Text('time-step').tr(),
                      SizedBox(
                        height: 5.0,
                      ),
                      CupertinoSegmentedControl(
                        groupValue: timeStep,
                        children: {
                          '30': Text('30'),
                          '60': Text('60'),
                        },
                        onValueChanged: (value) {
                          setState(() {
                            timeStep = value;
                          });
                        },
                      ),
                    ],
                  ),
          ],
        ),
      ),
    );
  }
}

显示错误的确切代码:

ManualInputBloc manualInputBloc;
manualInputBloc.close();

manual_input_bloc.dart

import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:dart_otp/dart_otp.dart';
import 'package:meta/meta.dart';

part 'manual_input_event.dart';
part 'manual_input_state.dart';

class ManualInputBloc extends Bloc<ManualInputEvent, ManualInputState> {
  ManualInputBloc() : super(ManualInputInitial());

  @override
  Stream<ManualInputState> mapEventToState(
    ManualInputEvent event,
  ) async* {
    if (event is GetFormTextEvent) {
      if (event.secretKey == null ||
          event.issuer == null ||
          event.accountName == null) {
        yield ManualInputError(
            'all-fields-error-title', 'all-fields-error-content');
      } else {
        try {
          final TOTP totp = TOTP(
            secret: event.secretKey,
            digits: int.parse(event.numberOfDigits),
            interval: int.parse(event.timeStep),
          );

          final String otp = totp.now();

          yield ManualInputFinal(
            otp,
            event.issuer,
            event.accountName,
          );
        } catch (error) {
          yield ManualInputError('totp-fail-title', 'totp-fail-content');
          print(error.toString());
        }
      }
    }
  }
}

【问题讨论】:

    标签: flutter dart bloc


    【解决方案1】:

    那是因为你没有初始化manualinputBloc。在这种情况下,该集团将为空。

    你应该先初始化你的变量:

    ManualInputBloc manualInputBloc = ManualInputBloc();
    

    编辑:

    在 bloc 的 builder 方法中也不是启动或关闭 bloc 的合适位置。这就是您想要更改状态类的方式:

    class _yourState extends State<YourState> {
     ManualInputBloc manualInputBloc;
    
     @override
     void initState() {
       manualInputBloc = ManualInputBloc();
       manualInputBloc.add(YourEvent());
     }
    
     @override
     void dispose() {
       manualInputBloc.close();
       super.dispose();
     }
    
     @override
     Widget build(BuildContext context) {
       return BlocBuilder<ManualInputBloc, ManualInputState>(
         cubit: manualInputBloc,
         builder: (context, state) {
           return YourWidget();
         }
     }
    

    【讨论】:

    • 这很有趣,因为当我初始化这个类时,应用程序实际上停止了工作。当我在没有初始化类的情况下执行“关闭”方法时,它就像一个魅力,但在调试控制台中有一个错误。
    • 这是因为您在错误的位置初始化变量。我会在一分钟内编辑我的答案
    • 我编辑了我的答案,如果还有什么问题请告诉我!
    • 知道为什么会这样吗?
    • 嗯,在你的按钮中,你正在使用 blocprovider.of,所以现在使用的是两个不同的 bloc 实例。也许将 blocprovider.of 更改为 manualInputbloc
    【解决方案2】:

    首先,您可能需要了解什么是 BLOC、什么是 Event 以及什么是 State。 您不能只关闭()块,因为它会在您的屏幕上执行某些操作。 状态是应用程序为用户服务的东西。您的状态应具有如下名称:DisplayingForm、ValidatingForm、DisplayingError、DisplayingSuccess。 事件是用户点击的东西。您的事件应具有如下名称:AddDataEvent(您只有一个,因此这在您的应用中并不重要)

    常见的流程是: 第一个状态是 DisplayingForm -> 用户单击 Add -> 状态更改为 ValidatingForm 然后有一个分叉 -> 成功 DisplayingSuccess -> 错误 DisplayingError。

    我想在成功后做点什么,比如关闭窗口,然后 if(state is DisplayingSuccess) Navigator.pop();或者您可以在 pop() 之前设置一些计时器延迟; 或者你可以 if(state is DisplayingSuccess) BlocProvider.of(context).add(ResetFormEvent),但是你需要在你的 bloc 中处理一个事件 ResetFormEvent,它最终将再次产生 DisplayingForm 状态。 您应该使用 .add(SomeEvent) 而不是 .close() 方法与 bloc 进行通信。 Cubit 是一种可以在其上执行方法而不是事件的块。

    【讨论】:

      猜你喜欢
      • 2022-11-17
      • 1970-01-01
      • 2020-04-25
      • 2021-08-06
      • 1970-01-01
      • 2020-02-23
      • 2020-01-11
      • 2021-02-11
      • 2021-06-10
      相关资源
      最近更新 更多