我有一个简单的 Flutter 插件,它通过MethodChannel
一些原生 Android 代码进行通信。这是一个简单的示例,插件提供的方法如下所示:
Future<void> doSomethingImportant(int address, SomeImportantData importantData) async {
String jsonButStillImportant = jsonEncode(importantData.toJson());
return methodChannel.invokeMethod('doSomethingImportant', {"address": address, "data": jsonButStillImportant});
}
当doSomethingImportant()
(java) 方法完成后,它通过调用将结果传递给 Flutter:
public void onSuccess(Result result, Object value) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
result.success(value);
Log.d("Debug", "Why does this occasionally cause a timeout at Flutter?!?");
}
});
}
然后,在测试期间,该方法被这样调用:
void _someTestMethod() async {
await doSomethingImportant(anAddress, theMostImportantDataInTheWorld).timeout(const Duration(seconds: 1)).catchError((e) {
print("Something's wrong here: "+e.toString());
return;
});
}
这在大多数情况下运行良好。但是,有时测试会因为doSomethingImportant()
超时而失败,并且 logcat 会显示以下内容:
2021-12-15 19:56:50.919 D/Debug: Why does this occasionally cause a timeout at Flutter?!?"
2021-12-15 19:56:51.697 I/flutter: Something's wrong here: TimeoutException after 0:00:01.000000: Future not completed
现在我想知道什么可能导致超时以及如何防止它。值得注意的是,超时消息总是在result.success()
调用后大约 700-800 毫秒出现。
编辑1:
问题是有时未来不会完成,即使result.success()
被调用。这只是偶尔发生,但如果发生,超时目的是优雅地退出调用函数。不幸的是,简单地删除超时不是一种选择,因为它会永远阻塞。
编辑 2 - 更多背景信息:
请注意,上面的代码片段doSomethingImportant()
和_someTestMethod()
只是说明方法外观的示例。(除了onSuccess()
,这是生产代码的精确副本)。
实际的插件控制蓝牙 Mesh 网络。_someTestMethod()
发送和接收数据以验证网状网络和在各个节点上运行的固件是否正在执行它们应该执行的操作。中的逻辑_someTestMethod()
如下所示:
- 将数据发送到网格中。
- 从网格中读取数据。
- 验证读取的数据是否与预期结果匹配。
选择该await/timeout()
方法是因为每个步骤都取决于上一步的成功完成。将这些调用嵌套在.then()
回调中是一种替代方法,但我只是更喜欢从上到下的await/timeout()
意大利面条代码而不是嵌套.then()
回调。
问题是,MethodChannel.Result.success()
在 Android 上时不时地调用它,但 Flutter 并没有完成Future
. 如果发生这种情况,Future 将永远保持未完成状态,并且 logcat 也不会提供任何信息。
同样,这种情况只是偶尔发生。大多数时候它工作得很好。
现在的问题是,这里有什么问题?有没有其他方法可以说服Future
完成?欢迎任何想法谢谢!