Flutter 如何在执行invokeMethod()时侦听异步响应?
我正在开发一个小的颤振应用程序,我使用一个本地库进行一些计算。dart和java(在android上)之间的通信是双向的,并使用MethodChannel实现。 我从dart调用_channel.invokeMethod(“someJavaMethod”)中的wait来开始计算。这将从Java触发本机库的初始化。此初始化的结果作为异步JNI调用返回,然后触发out_channel.invokeMethod(“someDartMethod”) 我的计划是将out_频道绑定到本地dart广播流,这样我就可以调用someJavaMethod,然后等待myMethodStream 问题是“someDartMethod”可能在“someJavaMethod”调用返回之前出现 我拥有的组合代码示例:Flutter 如何在执行invokeMethod()时侦听异步响应?,flutter,dart,Flutter,Dart,我正在开发一个小的颤振应用程序,我使用一个本地库进行一些计算。dart和java(在android上)之间的通信是双向的,并使用MethodChannel实现。 我从dart调用_channel.invokeMethod(“someJavaMethod”)中的wait来开始计算。这将从Java触发本机库的初始化。此初始化的结果作为异步JNI调用返回,然后触发out_channel.invokeMethod(“someDartMethod”) 我的计划是将out_频道绑定到本地dart广播流,这样
static const MethodChannel _channel_in = const
MethodChannel('native_lib_wrapper_out');
static const MethodChannel _channel_out = const
MethodChannel('native_lib_wrapper_in');
final StreamController<MethodCall> _methodStreamController = new
StreamController.broadcast();
NativeLibWrapper._() {
_channel_in.setMethodCallHandler((MethodCall call) {
_methodStreamController.add(call);
return;
});
}
Future<Map<dynamic,dynamic>> initLib(String id, String filePath)
async {
Map<dynamic,dynamic> ret;
ret = await _channel_out.invokeMethod("initLib", <String,
dynamic> { // data to be passed to the function
'id': id,
'filePath': filePath,
});
print('initLib - invokeMethod done. wait for stream');
if(ret["status"] == 0) {
await NativeLibWrapper.instance._methodStream
.where((m) => m.method == "libInitEnded")
.map((m){
var args = m.arguments;
ret = args;
}).first;
}
return ret;
}
static const MethodChannel\u channel\u in=const
MethodChannel('native_lib_wrapper_out');
静态常量方法通道_通道_输出=常量
MethodChannel('native_lib_wrapper_in');
最终StreamController _methodStreamController=新
StreamController.broadcast();
NativeLibWrapper.(){
_setMethodCallHandler((MethodCall调用)中的通道_{
_methodStreamController.add(调用);
返回;
});
}
Future initLib(字符串id、字符串文件路径)
异步的{
地图检索;
ret=wait _channel _out.invokeMethod(“initLib”),{//要传递给函数的数据
“id”:id,
“文件路径”:文件路径,
});
打印('initLib-invokeMethod done.wait for stream');
如果(ret[“状态”]==0){
等待NativeLibWrapper.instance.\u methodStream
其中((m)=>m.method==“libinitend”)
.map((m){
var args=m.arguments;
ret=args;
}).首先;
}
返回ret;
}
<>我希望代码能在我的流中获得方法调用LBIN,然后在那个点之后返回它,但是它一直挂在等待流上,从日志中看,在中间打印之前调用LiBiTeNebug。p>
那么,有没有更好的方法来构建这个?这将不是唯一来回的方法,所以我希望能得到一个很好的稳定解决方案。一个通道
您应该只需要一个频道。不需要输入和输出通道。两端可以通过一个通道调用另一端的操作
只有一个UI线程
从Dart调用本机时,本机方法由本机UI线程处理。除非您使用的是线程池,否则这意味着Dart到本机方法是按顺序处理的。不等待每个本机方法的答案是没有意义的。或者,换句话说,同时启动两个本机方法没有意义,因为它们将由单个本机线程连续执行。(请注意,您不应该在本机线程上执行耗时的操作,因为这会干扰它所做的其他事情,如手势检测。)每个“省道到本机”方法都应该返回其结果
使用线程池
如果一次线程/单方法调用是不可接受的,请考虑本地端的线程池。现在您可以使用多个方法,因为有多个执行线程。现在,您应该像通过套接字与服务器通信一样设计呼叫/响应。客户端为每个请求提供一个“调用id”。每个方法只返回请求排队的布尔值。请求完成后,另一端调用“done”方法,传递原始id和结果。然后,调用方可以将响应id与请求id相匹配,并适当地处理响应(并取消为检测超时而启动的任何计时器)。请注意,响应可以以任何顺序到达,但通过id与它们的请求匹配
在Android上,必须在
UIThread
上调用本机到Dart方法。如果从工作线程调用“done”方法,则需要将post
aRunnable
lambda发送到主循环器。提到的线程池是我最终希望通过此解决方案实现的,但实际上最后一段是解决问题的一段。结果表明,调用了本机到dart方法调用,但从未执行,因为它不在UI线程中。简单地把它放在UI线程上就解决了问题,我的初始代码按预期工作。谢谢你详尽的回答。链接到使用线程池的技术将非常有用,一个小示例将是最好的