You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

更换Dialogflow凭证后出现LateInitializationError问题求助

问题:替换Dialogflow凭证后出现LateInitializationError错误

上周代码运行正常,替换过期的新凭证后,代码抛出以下错误:

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: LateInitializationError: Field 'dialogflow' has not been initialized

相关代码如下:

import 'package:dialogflow_grpc/dialogflow_grpc.dart';
import 'package:dialogflow_grpc/generated/google/cloud/dialogflow/v2beta1/session.pb.dart';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class Chat extends StatefulWidget {
  Chat({Key? key}) : super(key: key);
  @override
  _ChatState createState() => _ChatState();
}
class _ChatState extends State<Chat> {
  final List<ChatMessage> _messages = <ChatMessage>[];
  final TextEditingController _textController = TextEditingController();

  late DialogflowGrpcV2Beta1 dialogflow;

  @override
  void initState() {
    super.initState();
    initPlugin();
  }

  Future<void> initPlugin()async{
    final serviceAccount = ServiceAccount.fromString(
        '${(await rootBundle.loadString('assets/credentials2.json'))}');
    // Create a DialogflowGrpc Instance
    dialogflow = DialogflowGrpcV2Beta1.viaServiceAccount(serviceAccount);
  }
  void handleSubmitted(text) async {
    print(text);
    _textController.clear();
    ChatMessage message = ChatMessage(
      text: text,
      name: "You",
      type: true,
    );

    setState(() {
      _messages.insert(0, message);
    });

    DetectIntentResponse data = await dialogflow.detectIntent(text, 'en-US');
    String fulfillmentText = data.queryResult.fulfillmentText;
    if(fulfillmentText.isNotEmpty) {
      ChatMessage botMessage = ChatMessage(
        text: fulfillmentText,
        name: "Bot",
        type: false,
      );

      setState(() {
        _messages.insert(0, botMessage);
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Chatbot Page'),
      ),
      body: Column(children: <Widget>[
        Flexible(
            child: ListView.builder(
              padding: EdgeInsets.all(8.0),
              reverse: true,
              itemBuilder: (_, int index) => _messages[index],
              itemCount: _messages.length,
            )),
        Divider(height: 1.0),
        Container(
            decoration: BoxDecoration(color: Theme.of(context).cardColor),
            child: IconTheme(
              data: IconThemeData(color: Theme.of(context).accentColor),
              child: Container(
                margin: const EdgeInsets.symmetric(horizontal: 8.0),
                child: Row(
                  children: <Widget>[
                    Flexible(
                      child: TextField(
                        controller: _textController,
                        onSubmitted: handleSubmitted,
                        decoration: InputDecoration.collapsed(hintText: "Send a message to begin"),
                      ),
                    ),
                    Container(
                      margin: EdgeInsets.symmetric(horizontal: 4.0),
                      child: IconButton(
                        icon: Icon(Icons.send),
                        onPressed: () => handleSubmitted(_textController.text),
                      ),
                    ),
                  ],
                ),
              ),
            )
        ),
      ]),
    );
  }
}

class ChatMessage extends StatelessWidget {
  ChatMessage({required this.text, required this.name, required this.type});

  final String text;
  final String name;
  final bool type;

  List<Widget> otherMessage(context) {
    return <Widget>[
      new Container(
        margin: const EdgeInsets.only(right: 16.0),
        child: CircleAvatar(child: new Text('B')),
      ),
      new Expanded(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Text(this.name,
                style: TextStyle(fontWeight: FontWeight.bold)),
            Container(
              margin: const EdgeInsets.only(top: 5.0),
              child: Text(text),
            ),
          ],
        ),
      ),
    ];
  }

  List<Widget> myMessage(context) {
    return <Widget>[
      Expanded(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.end,
          children: <Widget>[
            Text(this.name, style: Theme.of(context).textTheme.subtitle1),
            Container(
              margin: const EdgeInsets.only(top: 5.0),
              child: Text(text),
            ),
          ],
        ),
      ),
      Container(
        margin: const EdgeInsets.only(left: 16.0),
        child: CircleAvatar(
            child: Text(
              this.name[0],
              style: TextStyle(fontWeight: FontWeight.bold),
            )),
      ),
    ];
  }
  @override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.symmetric(vertical: 10.0),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: this.type ? myMessage(context) : otherMessage(context),
      ),
    );
  }
}

原因分析与解决办法

核心原因

initPlugin()是异步方法,initState中调用时不会等待它执行完毕。替换新凭证后,凭证加载、Dialogflow实例初始化的耗时可能变长,若用户在初始化完成前发送消息,就会触发LateInitializationError。

解决方法1:添加加载状态,禁用输入直到初始化完成

在状态类中新增加载状态变量,初始化完成前禁止用户交互:

class _ChatState extends State<Chat> {
  final List<ChatMessage> _messages = <ChatMessage>[];
  final TextEditingController _textController = TextEditingController();
  late DialogflowGrpcV2Beta1 dialogflow;
  bool _isInitializing = true; // 新增加载状态

  @override
  void initState() {
    super.initState();
    _initPlugin();
  }

  Future<void> _initPlugin() async {
    try {
      final serviceAccount = ServiceAccount.fromString(
          '${(await rootBundle.loadString('assets/credentials2.json'))}');
      dialogflow = DialogflowGrpcV2Beta1.viaServiceAccount(serviceAccount);
    } catch (e) {
      // 处理凭证加载失败的提示
      setState(() {
        _messages.insert(0, ChatMessage(text: "初始化失败:$e", name: "系统", type: false));
      });
    } finally {
      setState(() {
        _isInitializing = false; // 初始化完成,更新状态
      });
    }
  }

  // ... 其他代码不变

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Chatbot Page')),
      body: Column(children: <Widget>[
        Flexible(child: ListView.builder(
          padding: EdgeInsets.all(8.0),
          reverse: true,
          itemBuilder: (_, int index) => _messages[index],
          itemCount: _messages.length,
        )),
        Divider(height: 1.0),
        Container(
          decoration: BoxDecoration(color: Theme.of(context).cardColor),
          child: IconTheme(
            data: IconThemeData(color: Theme.of(context).accentColor),
            child: Container(
              margin: const EdgeInsets.symmetric(horizontal: 8.0),
              child: Row(
                children: <Widget>[
                  Flexible(
                    child: TextField(
                      controller: _textController,
                      onSubmitted: _isInitializing ? null : handleSubmitted,
                      decoration: InputDecoration.collapsed(
                        hintText: _isInitializing ? "正在初始化..." : "Send a message to begin"
                      ),
                      enabled: !_isInitializing, // 禁用未初始化状态的输入框
                    ),
                  ),
                  Container(
                    margin: EdgeInsets.symmetric(horizontal: 4.0),
                    child: IconButton(
                      icon: Icon(Icons.send),
                      onPressed: _isInitializing ? null : () => handleSubmitted(_textController.text),
                      disabledColor: Colors.grey,
                    ),
                  ),
                ],
              ),
            ),
          )
        ),
      ]),
    );
  }
}

解决方法2:将dialogflow改为可空类型,调用前检查

把late声明改为可空类型,在发送消息前判断是否初始化完成:

class _ChatState extends State<Chat> {
  final List<ChatMessage> _messages = <ChatMessage>[];
  final TextEditingController _textController = TextEditingController();
  DialogflowGrpcV2Beta1? dialogflow; // 改为可空类型

  @override
  void initState() {
    super.initState();
    _initPlugin();
  }

  Future<void> _initPlugin() async {
    final serviceAccount = ServiceAccount.fromString(
        '${(await rootBundle.loadString('assets/credentials2.json'))}');
    dialogflow = DialogflowGrpcV2Beta1.viaServiceAccount(serviceAccount);
  }

  void handleSubmitted(text) async {
    if (dialogflow == null) {
      setState(() {
        _messages.insert(0, ChatMessage(text: "正在初始化,请稍后再试", name: "系统", type: false));
      });
      _textController.clear();
      return;
    }

    // 原有业务逻辑
    print(text);
    _textController.clear();
    ChatMessage message = ChatMessage(
      text: text,
      name: "You",
      type: true,
    );

    setState(() {
      _messages.insert(0, message);
    });

    DetectIntentResponse data = await dialogflow!.detectIntent(text, 'en-US');
    String fulfillmentText = data.queryResult.fulfillmentText;
    if(fulfillmentText.isNotEmpty) {
      ChatMessage botMessage = ChatMessage(
        text: fulfillmentText,
        name: "Bot",
        type: false,
      );

      setState(() {
        _messages.insert(0, botMessage);
      });
    }
  }

  // ... 其他代码不变
}

额外建议

  • 确认新凭证文件credentials2.json的路径是否正确,保证rootBundle.loadString能读取到文件
  • 在_initPlugin中添加日志打印,排查初始化过程中的问题:
    Future<void> _initPlugin() async {
      try {
        final creds = await rootBundle.loadString('assets/credentials2.json');
        print("凭证加载成功:${creds.length}字符");
        final serviceAccount = ServiceAccount.fromString(creds);
        dialogflow = DialogflowGrpcV2Beta1.viaServiceAccount(serviceAccount);
        print("Dialogflow实例初始化完成");
      } catch (e) {
        print("初始化失败:$e");
      }
    }
    

内容的提问来源于stack exchange,提问作者Lim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 18:25:22