在执行invokeMethod()时如何监听异步响应?

时间:2019-07-31 13:34:01

标签: flutter dart

我正在开发一个小型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在打印之前已被调用在中间。

那么有没有更好的方法来构造这个?它不是来回移动的唯一方法,所以我希望为此找到一个好的稳定解决方案。

1 个答案:

答案 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到主循环程序。