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

Dart使用xmpp_stone插件时如何修复空检查报错问题

Dart xmpp_stone插件空检查报错修复
  • 开发语言:Dart
  • 问题描述:使用xmpp_stone插件开发XMPP通信功能时触发空检查报错,无法独立完成修复
  • 报错截图:xmpp_stone空检查报错截图

问题关联原始代码

import 'dart:io';
import 'package:xmpp_stone/src/logger/Log.dart';
import 'package:console/console.dart';
import 'dart:async';
import 'dart:convert';
import 'package:xmpp_stone/xmpp_stone.dart' as xmpp;
import 'package:image/image.dart' as image;
final String TAG = 'example';

class ExampleConnectionStateChangedListener implements xmpp.ConnectionStateChangedListener {
  late xmpp.Connection _connection;
  late xmpp.MessagesListener _messagesListener;

  StreamSubscription<String>? subscription;

  ExampleConnectionStateChangedListener(xmpp.Connection connection, xmpp.MessagesListener messagesListener) {
    _connection = connection;
    _messagesListener = messagesListener;
    _connection.connectionStateStream.listen(onConnectionStateChanged);
  }

  @override
  void onConnectionStateChanged(xmpp.XmppConnectionState state) {
    if (state == xmpp.XmppConnectionState.Ready) {
      Log.d(TAG, 'Connected');
     _connection.getMamModule().queryAll();
      var vCardManager = xmpp.VCardManager(_connection);
      vCardManager.getSelfVCard().then((vCard) {
        if (vCard != null) {
          Log.d(TAG, 'Your info' + vCard.buildXmlString());
        }
      });
      var messageHandler = xmpp.MessageHandler.getInstance(_connection);
      var rosterManager = xmpp.RosterManager.getInstance(_connection);
      messageHandler.messagesStream.listen(_messagesListener.onNewMessage);
      sleep(const Duration(seconds: 1));
      var receiver = 'yyy@gmail.com';
      var receiverJid = xmpp.Jid.fromFullJid(receiver);
      rosterManager.addRosterItem(xmpp.Buddy(receiverJid)).then((result) {
        if (result.description != null) {
          print("TAG, 'add roster'" + result.description!);
        }
      });
      sleep(const Duration(seconds: 1));
      vCardManager.getVCardFor(receiverJid).then((vCard) {
        if (vCard != null) {
          print("TAG, 'Receiver info'" + vCard.buildXmlString());
          if (vCard != null && vCard.image != null) {
            var file = File('test456789.jpg')..writeAsBytesSync(image.encodeJpg(vCard.image!));
            print("TAG, IMAGE SAVED TO: ${file.path}");
          }
        }
      });
      var presenceManager = xmpp.PresenceManager.getInstance(_connection);
      presenceManager.presenceStream.listen(onPresence);

    }
  }

  void onPresence(xmpp.PresenceData event) {
    Log.d(TAG, 'presence Event from ' + event.jid!.fullJid! + ' PRESENCE: ' + event.showElement.toString());
  }
}

Stream<String> getConsoleStream() {
  return Console.adapter.byteStream().map((bytes) {
    var str = ascii.decode(bytes);
    str = str.substring(0, str.length - 1);
    return str;
  });
}

class ExampleMessagesListener implements xmpp.MessagesListener {

  @override
  void onNewMessage(xmpp.MessageStanza? message) {
    if (message!.body != null) {
      Log.d(TAG ,format(
          'New Message from {color.blue}${message.fromJid!.userAtDomain}{color.end} message: {color.red}${message.body}{color.end}'));
    }
  }

  @override
  void onChatMessage(xmpp.MessageStanza? message) {
    print(message);
    if (message!.body != null) {
      Log.d(TAG,format(
          'New Message from {color.blue}${message.fromJid!.userAtDomain}{color.end} message: {color.red}${message.body}{color.end}'));
    }
  }
}

sendmessageforxmpp(){
  var userAtDomain = 'xxx@gmail.com';

  var password = 'password';
  var jid = xmpp.Jid.fromFullJid(userAtDomain);
  var account = xmpp.XmppAccountSettings(userAtDomain, jid.local, 
 jid.domain, password, 5222, resource: 'xmppstone');
  var connection = xmpp.Connection(account);
  var receiver = 'yyy@gmail.com';
  var receiverJid = xmpp.Jid.fromFullJid(receiver);
Log.d(TAG, receiverJid.fullJid.toString());
  var messageHandler = 
   xmpp.MessageHandler.getInstance(connection); 
    messageHandler.sendMessage(receiverJid, "str");
}

报错根因与修复方案

所有空检查报错均来自Dart空安全机制下的不规范写法、逻辑时序错误,按以下点逐一修改即可解决:

  1. 修正消息监听的强制非空断言滥用问题
    原代码在onNewMessage、onChatMessage方法中直接对可空参数message使用!强制非空,一旦流中传入null值会直接触发空异常。替换为正常判空逻辑,同时去掉fromJid的强制非空断言:
@override
void onNewMessage(xmpp.MessageStanza? message) {
  if (message != null && message.body != null) {
    Log.d(TAG ,format(
        'New Message from {color.blue}${message.fromJid?.userAtDomain}{color.end} message: {color.red}${message.body}{color.end}'));
  }
}

@override
void onChatMessage(xmpp.MessageStanza? message) {
  print(message);
  if (message != null && message.body != null) {
    Log.d(TAG,format(
        'New Message from {color.blue}${message.fromJid?.userAtDomain}{color.end} message: {color.red}${message.body}{color.end}'));
  }
}
  1. 修正在线状态监听的空断言问题
    原代码在onPresence方法中直接对event.jid、fullJid使用强制非空断言,字段为空时直接崩溃。增加判空逻辑后再输出日志:
void onPresence(xmpp.PresenceData event) {
  final jidFull = event.jid?.fullJid;
  if (jidFull != null) {
    Log.d(TAG, 'presence Event from ' + jidFull + ' PRESENCE: ' + event.showElement.toString());
  }
}
  1. 修正发消息逻辑的时序错误
    原sendmessageforxmpp方法中,刚初始化连接对象就直接调用发消息接口,此时连接未建立、内部模块未初始化,必然触发空异常。需要等待连接状态变为Ready后再执行发消息操作:
sendmessageforxmpp() async {
  var userAtDomain = 'xxx@gmail.com';
  var password = 'password';
  var jid = xmpp.Jid.fromFullJid(userAtDomain);
  var account = xmpp.XmppAccountSettings(userAtDomain, jid.local, 
 jid.domain, password, 5222, resource: 'xmppstone');
  var connection = xmpp.Connection(account);
  var receiver = 'yyy@gmail.com';
  var receiverJid = xmpp.Jid.fromFullJid(receiver);
  Log.d(TAG, receiverJid.fullJid.toString());
  // 发起连接
  connection.connect();
  // 等待连接就绪再发消息
  await for (final state in connection.connectionStateStream) {
    if (state == xmpp.XmppConnectionState.Ready) {
      var messageHandler = xmpp.MessageHandler.getInstance(connection); 
      messageHandler.sendMessage(receiverJid, "str");
      break;
    }
  }
}
  1. 替换阻塞式延迟方法
    原代码在异步回调中使用sleep会阻塞整个Dart事件循环,导致网络请求、模块初始化流程卡住,极易触发内部状态未初始化的空错误。所有sleep调用全部替换为非阻塞的Future.delayed:
// 替换原有的 sleep(const Duration(seconds: 1));
await Future.delayed(const Duration(seconds: 1));
  1. 清理冗余判空逻辑
    原代码判断vCard != null后又重复判断一次vCard非空,直接删除内层重复的vCard判空即可,不影响逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 01:06:21