【问题标题】:Invoked Flutter plugin methods will not complete when they are using completable futures in Android在 Android 中使用可完成的期货时,调用的 Flutter 插件方法将无法完成
【发布时间】:2021-09-10 21:13:20
【问题描述】:

我正在构建一个 Android 独有的 Flutter 插件,该插件将严重依赖其 Android 端的异步任务。为此,我正在尝试构建一个简单的示例,该示例使用 Java 中的 CompletableFutures 以模拟延迟测试这种通信。我用

创建了这个项目
flutter create --org org.example --template=plugin --platforms=android -a java zcspos

我的示例代码只是延迟回显:

ZcsposPlugin.java

    private CompletableFuture<Void> waitAsync(int milliseconds) {
        return CompletableFuture.runAsync(() -> {
            try {
                Thread.sleep(milliseconds);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
    }

    @Override
    public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result) {
        switch (call.method) {
            case "echo": {
                final String value = call.argument("value");
                this.waitAsync(1000).thenRunAsync(() -> { // wait 1 second
                    Log.d(this.TAG, "Echoing '" + value + "'");
                    result.success(value);
                });
                break;
            }
            default:
                result.notImplemented();
        }
    }

zcspos.dart

  static Future<String?> echo(String value) async {
    return await _channel.invokeMethod<String>('echo', <String, dynamic>{'value': value});
  }

ma​​in.dart

  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
        ),
        body: Container(
          margin: EdgeInsets.all(8),
          child: Center(
            child: Column(
              children: [
                RawMaterialButton(
                    padding: EdgeInsets.all(8),
                    fillColor: Colors.blue,
                    highlightColor: Colors.blueAccent,
                    child: Text(
                      "ECHO TEST",
                      style: TextStyle(
                        fontWeight: FontWeight.bold,
                        color: Colors.white,
                      ),
                    ),
                    onPressed: () async {
                      try {
                        print(await Zcspos.echo("Echo 1"));
                        print(await Zcspos.echo("Echo 2"));
                        print(await Zcspos.echo("Echo 3"));
                      } catch (e) {
                        print(e.toString());
                      }
                    }),
              ],
            ),
          ),
        ),
      ),
    );
  }

输出只有:

Echoing 'Echo 1'

但应该是:

Echoing 'Echo 1'
Echo 1
Echoing 'Echo 2'
Echo 2
Echoing 'Echo 3'
Echo 3

我调试了 Android 代码,它正确地调用了result.success

我该如何解决这个问题?

【问题讨论】:

    标签: android dart flutter-plugin


    【解决方案1】:

    在编写问题时得到了解决方案,因此它可能对将来的某人有用。

    结果应该在主线程上实现,它不会在不同的线程上工作。一种可能的解决方案是make sure to have access to the Activity,然后您可以简单地将result.success 包装成runOnUiThread()

    Zcspos.java

    public class ZcsposPlugin implements FlutterPlugin, MethodCallHandler, ActivityAware {
        private Activity activity;
        private MethodChannel channel;
    
        @Override
        public void onAttachedToActivity(ActivityPluginBinding binding) {
            this.activity = binding.getActivity();
        }
    
        @Override
        public void onReattachedToActivityForConfigChanges(ActivityPluginBinding binding) {
            this.activity = binding.getActivity();
        }
    
        @Override
        public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
            channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "zcspos");
            channel.setMethodCallHandler(this);
        }
    
        private CompletableFuture<Void> waitAsync(int milliseconds) {
            return CompletableFuture.runAsync(() -> {
                try {
                    Thread.sleep(milliseconds);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
    
        @Override
        public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result) {
            switch (call.method) {
                case "echo": {
                    final String value = call.argument("value");
                    this.waitAsync(1000).thenRunAsync(() -> {
                        this.activity.runOnUiThread(() -> { // <- HERE WE GO
                            Log.d(this.TAG, "Echoing '" + value + "'");
                            result.success(value);
                        });
                    });
                    break;
                }
                default:
                    result.notImplemented();
            }
        }
    
        @Override
        public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
            channel.setMethodCallHandler(null);
        }
    
        @Override
        public void onDetachedFromActivityForConfigChanges() {
            this.activity = null;
        }
    
        @Override
        public void onDetachedFromActivity() {
            this.activity = null;
        }
    

    不确定这是否是最好的解决方案,但它就像魅力一样。

    【讨论】:

      猜你喜欢
      • 2019-12-12
      • 2018-09-02
      • 2021-12-10
      • 1970-01-01
      • 1970-01-01
      • 2020-04-22
      • 2018-05-19
      • 1970-01-01
      • 2019-09-26
      相关资源
      最近更新 更多