我正在使用 StompClient 连接到我的游戏服务器 Websocket 端点。为了使用 Flutter 的
FutureBuilder
,我希望此客户端具有异步/等待功能。
因此我通过以下方式包装了StompClient:
class CombatClient {
late StompClient _client;
Future<bool> connect() async {
_client = StompClient(
config: StompConfig.SockJS(
url: '${ServerGlobals.backendHost}/connect',
onConnect: (frame) async {
_client.subscribe(destination: "/gameserver/foo", callback: (data) => {print("foo: ${data.body}")});
},
),
);
_client.activate();
return await Future.doWhile(() => _client.connected);
}
}
在我的主要逻辑中,我使用这样的整体:
final combatClient = CombatClient();
await combatClient.connect();
但是由于以下错误,这不起作用:
E/flutter (23147): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: type 'Null' is not a subtype of type 'FutureOr<bool>'
E/flutter (23147): #0 CombatClient.connect (package:app/combat/websocket/combat_client.dart:19:12)
E/flutter (23147): <asynchronous suspension>
E/flutter (23147): #1 _DebugCombatPageState.build.<anonymous closure> (package:app/debug/debug_combat_page.dart:61:27)
E/flutter (23147): <asynchronous suspension>
E/flutter (23147):
无论错误如何,我只是想知道正确的方法是什么。当涉及到期货等时,我总是很挣扎。我找不到正确的 API 用法来连接到游戏服务器awaitable。
引自@pskink
简单地使用 Completer 类而不是 return wait Future.doWhile(... - 文档说:“一种生成 Future 对象并稍后用值或错误完成它们的方法”
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:stomp_dart_client/stomp.dart';
import 'package:stomp_dart_client/stomp_frame.dart';
import 'package:stomp_dart_client/stomp_config.dart';
extension FutureHelper<T> on Future<T> {
static Future<void> doWhileByDuration(FutureOr<bool> Function() action, {Duration duration = Durations.extralong4}) => Future.doWhile(() => Future.sync(action).then((isDone) => isDone ? Future.delayed(duration, () => true) : Future.value(false)));
}
class CombatClient {
late StompClient _client;
Future<void> connect() {
_client = StompClient(
config: StompConfig.SockJS(
url: '${ServerGlobals.backendHost}/connect',
onConnect: (frame) async {
_client.subscribe(destination: "/gameserver/foo", callback: (data) => {print("foo: ${data.body}")});
},
),
);
_client.activate();
return FutureHelper.doWhileByDuration(() => !_client.connected, duration: Durations.long2);
}
}
或者:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:stomp_dart_client/stomp.dart';
import 'package:stomp_dart_client/stomp_frame.dart';
import 'package:stomp_dart_client/stomp_config.dart';
class CombatClient {
final Completer _completer = Completer<bool>();
late StompClient _client;
Future<bool> connect() async {
_client = StompClient(
config: StompConfig.SockJS(
url: '${ServerGlobals.backendHost}/connect',
onStompError: (frame) {
_completer.complete(false);
},
onConnect: (frame) async {
_client.subscribe(destination: "/gameserver/foo", callback: (data) => {print("foo: ${data.body}")});
_completer.complete(true);
},
),
);
_client.activate();
return _completer.future;
}
}