我正在开发一个小型flutter应用程序,在其中我使用本机库进行一些计算。 dart与Java之间的通信是双向的(在android上),为此使用methodChannels。 我从dart调用await in_channel.invokeMethod(“ someJavaMethod”)开始计算。这将触发Java的本机库的初始化。此初始化的结果将作为异步JNI调用返回,该调用随后触发out_channel.invokeMethod(“ someDartMethod”)。
我的计划是将out_channel绑定到本地dart广播流,以便我可以调用someJavaMethod,然后等待myMethodStream.where((m)=> m.method ==“ someDartMethod”)...
问题是“ someDartMethod”可以在“ someJavaMethod”调用调用返回之前出现。
我所拥有的组合代码示例:
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;
}
我本来希望代码在我的流上获取方法调用libInitEnded,然后应在该点之后返回,但它会继续挂在流上等待,并且从日志中看起来好像libInitEnded在打印之前已被调用在中间。
那么有没有更好的方法来构造这个?它不是来回移动的唯一方法,所以我希望为此找到一个好的稳定解决方案。
答案 0 :(得分:1)
一个频道
您只需要一个频道即可。无需进出频道。两端可以通过一个通道在另一端调用操作。
只有一个UI线程
当您从Dart调用到Native时,native方法由本机UI线程处理。除非使用线程池,否则意味着Dart到Native方法是按顺序处理的。 not await
解释每种本机方法的答案毫无意义。或者换句话说,没有必要同时启动两个本机方法,因为它们将由单个本机线程连续执行。 (请注意,您不应在本机线程上执行耗时的操作,因为这会干扰它进行手势检测等其他操作。)每个Dart到本机方法都应返回其结果。
使用线程池
如果一次不能接受单个线程/单个方法,请考虑在本机端使用线程池。现在,您可以使用多种方法,因为有多个执行线程。现在,您应该像通过套接字与服务器进行通信那样设计呼叫/响应。客户端为每个请求提供一个“调用ID”。每个方法仅返回一个已将请求排队的布尔值。请求完成后,另一端将调用“ done”方法,并传递原始ID和结果。然后,调用方可以将响应ID与请求ID匹配,并适当地处理响应(并取消启动用于检测超时的任何计时器)。请注意,响应随后可以以任何顺序到达,但通过ID与请求相匹配。
在Android上,您必须在UIThread
上调用Dart方法的本机。如果要从工作线程调用'done'方法,则需要post
一个Runnable
lambda到主循环程序。