Flutter混合开发 BasicMessageChannel与原生android通信(4.3)

上一篇中,给大家介绍了android原生给flutter发送初始化数据,但是呢flutter不能返回数据给android原生,本篇给大家介绍的是BasicMessageChannel,可以完成android与flutter之间的相互通信!!

混合通讯的三种方式

  • BasicMessageChannel:双向通信,有返回值,持续通信

  • MethodChannel:双向通信,有返回值,一次性通信

  • EventChannel: 单向通信,无返回值 ,持续通信,收到消息后无法回复此次消息

先来看看今天要完成的效果吧:

在这里插入图片描述

还是咋们的老套路,先分析一下功能:

分析:

Android端:

  • 一个按钮,携带数据点击跳转到Flutter页面,
  • 一个EditText文本框输入文本内容
  • 完成Flutter数据的传递

Flutter端

  • 一个TextField()组件可以完成数据的返回并Toast
  • 一个RaisedButton()按钮,点击可以完成Toast的展示并且数据返回成功
  • 底部文本展示Android返回的数据

第一步;创建BasicMessageChannel()

(别急着复制,下边我会写成工具类!很好用)

 private final BasicMessageChannel<String> messageChannel;
 
messageChannel = new BasicMessageChannel(messenger, "BasicMessageChannelPlugin", StringCodec.INSTANCE);

BasicMessageChannel参数介绍:

  • BinaryMessenger messenger - 消息信使,是消息的发送与接收的工具;
  • String name - Channel的名字,也是其唯一标识符;
  • MessageCodec<T> codec - 消息的编解码器,他有如下表格类型
MessageCodec<T> codec类型介绍
BinaryCodec最为简单的一种Codec,因为其返回值类型和入参的类型相同,均为二进制格式(Android中为ByteBuffer)。实际上,BinaryCodec在编解码过程中什么都没做,只是原封不动将二进制数据消息返回而已
JSONMessageCodec用于基础数据与二进制数据之间的编解码,其支持基础数据类型以及列表、字典,在Android端则使用了其自定义的JSONUtil与StringCodec作为序列化工具
StringCodec用于字符串与二进制数据之间的编解码,其编码格式为UTF-8
StandardMessageCodec是BasicMessageChannel的默认编解码器,其支持基础数据类型、二进制数据、列表、字典,其工作原理;

第二步:设置消息处理器,处理来自Dart的消息

 //设置消息处理器,处理来自Dart的消息
        messageChannel.setMessageHandler(new BasicMessageChannel.MessageHandler<String>() {
            @Override
            public void onMessage(@Nullable String message, @NonNull BasicMessageChannel.Reply<String> reply) {
            //可以通过reply进行回复
			 reply.reply("BasicMessageChannel收到:" + message);
            }
        });

onMessage参数介绍:

  • 参数一,String message,就是收到的参数
  • 参数二:BasicMessageChannel.Reply<String> reply,当收到Flutter消息时,可以通过 reply.reply()立即返回一个数据

第三步,发送消息

 messageChannel.send(message, callback);

参数介绍:

  • 参数一:要发送的消息内容
  • 参数二:来自Dart的反馈(我觉得并没有什么用… )

将BasicMessageChannel封装成工具类:

import android.app.Activity;
import android.widget.Toast;

import io.flutter.Log;
import io.flutter.plugin.common.BasicMessageChannel;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.StringCodec;

/**
      szj 2020/11/26
     CSDN博客:https://blog.csdn.net/weixin_44819566/
     微信公众号:码上变有钱
 */
public class BasicMessageChannelPlugin implements BasicMessageChannel.MessageHandler<String> {
    private final Activity activity;
    private final BasicMessageChannel<String> messageChannel;

    public static BasicMessageChannelPlugin registerWith(BinaryMessenger messenger, Activity activity) {
        return new BasicMessageChannelPlugin(messenger, activity);
    }

    private BasicMessageChannelPlugin(BinaryMessenger messenger, Activity activity) {
        this.activity = activity;
        this.messageChannel = new BasicMessageChannel(messenger, "BasicMessageChannelPlugin", StringCodec.INSTANCE);
        //设置消息处理器,处理来自Dart的消息
        messageChannel.setMessageHandler(this);

    }

    @Override//处理Dart发来的消息
    public void onMessage(String s, BasicMessageChannel.Reply<String> reply) {
        reply.reply("BasicMessageChannel收到:" + s);//可以通过reply进行回复
        if (activity instanceof IShowMessage) {
            ((IShowMessage) activity).onShowMessage(s);
            Toast.makeText(activity, s, Toast.LENGTH_SHORT).show();
        }


    }

    /**
     * 向Dart发送消息,并接受Dart的反馈
     *
     * @param message  要给Dart发送的消息内容
     * @param callback 来自Dart的反馈
     */
   public void send(String message, BasicMessageChannel.Reply<String> callback) {
        messageChannel.send(message, callback);
    }

}

代码非常简单,有不懂的同学记得评论区留言哦~

第四步:写一个接口,用来定义获取和发送的数据:

public interface IShowMessage {
    /**
     *
     * @param message Flutter -> Android
     */
    void onShowMessage(String message);

    /**
     *
     * @param message Android --> flutter
     */
    void sendMessage(String message);
}

第五步:创建点击事件,跳转页面并传值

 EditText edit = findViewById(R.id.edit);

        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                FlutterAppActivity.start(BasicMsgChannelActivity.this,edit.getText().toString(),1);
            }
        });

这块代码有迷糊的同学请看上一章:Flutter混合开发 传递初始化数据给Android(4.2)

java代码(FlutterAppActivity类);

public class FlutterAppActivity extends FlutterActivity  implements IShowMessage{
    private BasicMessageChannelPlugin basicMessageChannelPlugin;

    public final static String INIT_PARAMS = "initParams";
    /**
     * 0 给Flutter传递初始化数据
     * 1 使用BasicMsgChannel传递数据
     */
    private static int mtype ;

    public static void start(Context context, String initParams, int type) {
        mtype = type;
        Intent intent = new Intent(context, FlutterAppActivity.class);
        intent.putExtra(INIT_PARAMS, initParams);
        context.startActivity(intent);
    }

    String mInitParam;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i("szjonCreate",mtype+"");
        if (mtype == 0) {
           // 给Flutter传递初始化数据
            mInitParam = getIntent().getStringExtra(INIT_PARAMS);

        }else if(mtype == 1){
            //使用BasicMsgChannel传递数据
            basicMessageChannelPlugin = BasicMessageChannelPlugin.registerWith(getFlutterEngine().getDartExecutor(), this);
        }

    }

    @Override
    protected void onStart() {
        super.onStart();
        if (mtype == 1) {
            String initParam = getIntent().getStringExtra(INIT_PARAMS);
            this.sendMessage(initParam);
        }

    }

    /**
     * 传递初始化参数给Flutter
     * @return
     */
    @NonNull
    @Override
    public String getInitialRoute() {
        return mInitParam == null ? super.getInitialRoute() : mInitParam;
    }

//         使用在MyApplication预先初始化好的Flutter引擎以提升Flutter页面打开速度,
//         注意:在这种模式下会导致getInitialRoute 不被调用所以无法设置初始化参数
//        @Override
//        public String getCachedEngineId() {
//            return App.ENG_INED;
//        }


    @Override
    public void onShowMessage(String message) {
        Log.i("szjonShowMessage",message);
    }

    @Override
    public void sendMessage(String message) {
        Log.i("szjsendMessage",message);
        if (basicMessageChannelPlugin == null) {
            return;
        }
        basicMessageChannelPlugin.send(getIntent().getStringExtra(INIT_PARAMS),this::onShowMessage);
    }
}

注意:
sendMessage()传递消息的方法一定要卸载onStart()方法里面

 @Override
    protected void onStart() {
        super.onStart();
        if (mtype == 1) {
            String initParam = getIntent().getStringExtra(INIT_PARAMS);
            this.sendMessage(initParam);
        }
    }

代码中的mtype是用来区分和上一章:Flutter混合开发 传递初始化数据给Android(4.2)的变量!

走到这里Android端的初始化就完成了,在简单的分析一下:

  • 在BasicMsgChannelActivity页面有一个按钮一个文本框,点击按钮调用了跳转FlutterAppActivity页面的方法**,FlutterAppActivity就是Flutter页面,因为FlutterAppActivity继承自FlutterActivity.然后在FlutterAppActivity的onCreate方法中使用工具类BasicMessageChannelPlugin**,这个工具类的作用是初始化BasicMessageChannel().在onStart()方法中调用send方法,给dart传值.

在来看看Flutter的代码吧:

第一步:初始化BasicMessageChannel()

//初始化BasicMessageChannel()
BasicMessageChannel<String> _basicMessageChannel =
      BasicMessageChannel('BasicMessageChannelPlugin', StringCodec());
  • 参数一:对应的是android代码中的BasicMessageChannel()这个参数,必须完全以一直

    在这里插入图片描述

    -参数二:编码模式,Android端和Flutter端的编码模式也呀一值

第二步:使用BasicMessageChannel接受来自Native的消息,并向Native回复


  String showMessage;

  @override
  void initState() {
    //使用BasicMessageChannel接受来自Native的消息,并向Native回复
    _basicMessageChannel
        .setMessageHandler((String message) => Future<String>(() {
              setState(() {
                showMessage = 'BasicMessageChannel:' + message;
              });
              return "BasicMessageChannel收到android的消息:" + message;
            }));
    super.initState();
  }
 RaisedButton(
      onPressed: () {
      _basicMessageChannel.send("我是Flutter的数据!!!");
      },
      child: Text("发送消息给native"),
      ),
     TextField(
        onChanged: _onTextChange,
        decoration: InputDecoration(
        hintText: "请输入给原生发送的消息",
          ),
    ),
    Text("BasicMessageChannel接收android原生数据为: ${showMessage}"),

建议使用异步操作发送消息;

  void _onTextChange(value) async {
    String response;
    /**
     * 在android对应的是 reply.reply()
     */
    response = await _basicMessageChannel.send(value);
    setState(() {
      showMessage =  response ;
    });
  }

走到这里就完成了,大家肯定看的有点迷糊,我讲的不太好,还要拿文字表达出来,表达的不是很完美,还是在总结一下吧:

Android给Flutter发消息使用

BasicMessageChannel messageChannel = BasicMessageChannel(参数一,参数二,参数三);
messageChannel.send(message, callback);

Android获取Flutter发送的消息使用:

 @Override//处理Dart发来的消息
  messageChannel.setMessageHandler(new BasicMessageChannel.MessageHandler<String>() {
            @Override
            public void onMessage(@Nullable String message, @NonNull BasicMessageChannel.Reply<String> reply) {
             reply.reply("我是android的代码reply:" + s);//可以通过reply进行回复
                Toast.makeText(activity, message, Toast.LENGTH_SHORT).show();
            }
        });
  • 这里的message就是Flutter给Android发送的消息,我用Toast显示出来了
  • 这里的reply.reply()是获取到Flutter数据之后回复Flutter的数据

Android端需要注意的就是send()方法一定要在onStart()方法里面,其实这么说也不完全对,应该是send()方法一定要在初始化BasicMessageChannel()方法后面,如果是在他前面send()会null

Flutter获取Android发送的数据使用:

//初始化BasicMessageChannel
 BasicMessageChannel<String> _basicMessageChannel =
      BasicMessageChannel('BasicMessageChannelPlugin', StringCodec());

_basicMessageChannel
        .setMessageHandler((String message) => Future<String>(() {
              setState(() {
                //Android --> Flutter
                showMessage = 'BasicMessageChannel:' + message;
              });
              return "BasicMessageChannel收到android的消息:" + message;
            }));

这里的message就是Android给Flutter发送的数据

如果获取Flutter发送给Android数据后,Android返回的数据:

String response = _basicMessageChannel.send(value);

发送数据后,send()的返回值就是Android返回的数据

在来看看效果吧:

在这里插入图片描述

你以为走到这里就完了吗?

肯定没有呀,难道你就不想知道跳转的时候为什么有黑屏???

如何解决呢?对于我这种杠精来说,尽量要做到完美~

其实上一章:Flutter混合开发 传递初始化数据给Android(4.2)已经说过了,只需要在FlutterAppActivity中吧

  @Override
        public String getCachedEngineId() {
            return App.ENG_INED;
        }

这段代码写上就好,getCachedEngineId()会导致getInitialRoute() 不被调用所以无法设置初始化参数,但是BasicMessageChannel()他可管不着~

来康康最终效果吧:

在这里插入图片描述

这个通信我搞了好几天,出了好多错,最终终于完成了这个,在接下来的几篇中我会介绍其他两个通信方式~

完整代码

上一章:Flutter混合开发 传递初始化数据给Android(4.2)

原创不易,您的点赞就是对我最大的支持,留下您的点赞吧~

原文地址:https://blog.csdn.net/weixin_44819566/article/details/110194380

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


简介 java中使用jar包来封装有用的功能,然后将其分发到maven仓库中,供其他人使用。同样的在dart中也有类似的概念叫做packages。packages就是可以用来共享的软件包,可以包含libraries和tools。 你可以在pub.dev网站中查到dart中所有的共享packages的
简介 flutter是google在2015年dart开发者峰会上推出的一种开源的移动UI构建框架,使用flutter可以非常方便的编译成运行在原始android,ios,web等移动平台上的移动应用。 flutter是使用dart来编写的,最新的flutter版本是2.5.3,而最新的Dart语言
简介 dart作为一种面向对象的语言,class是必不可少的。dart中所有的class,除了Null都继承自Object class。 要想使用dart中的类就要构造类的实例,在dart中,一个类的构造函数有两种方式,一起来看看吧。 传统的构造函数 和JAVA一样,dart中可以使用和class名
简介 Exception是程序中的异常情况,在JAVA中exception有checked Exception和unchecked Exception。那么在dart中的情况是不是一样的呢?一起来看看吧。 Exception和Error Dart中表示异常的类有两个,分别是Exception和Err
简介 虽然dart中的类只能有一个父类,也就是单继承的,但是dart提供了mixin语法来绕过这样限制。 今天,和大家一起来探讨一下dart类中的继承。 使用extends 和JAVA一样,dart中可以定义一个父类,然后使用extends来继承他,得到一个子类,如下所示: class Studen
简介 pubspec.yaml是所有dart项目的灵魂,它包含了所有dart项目的依赖信息和其他元信息,所以pubspec.yaml就是dart项目的meta! pubspec.yaml支持的字段 根据dart的定义,pubspec.yaml中可以包含下面的字段: 字段名 是否必须字段 描述 nam
dart系列之:dart语言中的特殊操作符 简介 有运算就有操作符,dart中除了普通的算术运算的操作符之外,还有自定义的非常特殊的操作符,今天带大家一起来探索一下dart中的特殊操作符。 普通操作符 普通操作符就很好解释了,就是加减乘除,逻辑运算符,比较运算符和位运算符等。 这些操作符和其他语言的
简介 在dart系统中,有pubspec.yaml文件的应用就可以被成为一个package。而Libray package是一类特殊的package,这种包可以被其他的项目所依赖. 也就是通常所说的库。 如果你也想你写的dart程序可以上传到pub.dev上,或者提供给别人使用,则来看看这篇文章吧。
简介 和所有的编程语言一样,dart有他内置的语言类型,这些内置类型都继承自Object,当然这些内置类型是dart语言的基础,只有掌握了这些内置类型才能够在使用dart语言的时候得心应手。 今天就给大家讲解一下dart语言的内置类型。 Null 在dart中用null来表示空。那么null和Nul
简介 函数是所有编程语言都有的内容,不管是面向对象还是面向过程,函数都是非常重要的一部分。dart中的函数和java中的函数有什么区别呢? dart作为一种面向对象的编程语言,它的函数也是一个对象,用Function来表示。先看下函数的定义: abstract class Function { ex
简介 熟悉JAVA的朋友可能知道,JAVA在8中引入了泛型的概念。什么是泛型呢?泛型就是一种通用的类型格式,一般用在集合中,用来指定该集合中应该存储的对象格式。 有了泛型可以简化我们的编程,并且可以减少错误的产生,非常的方便。 dart语言中也有泛型。一起来看看吧。 为什么要用泛型 使用泛型的主要目
简介 熟悉javascript的朋友应该知道,在ES6中引入了await和async的语法,可以方便的进行异步编程,从而摆脱了回调地狱。dart作为一种新生的语言,没有理由不继承这种优秀的品质。很自然的,dart中也有await和async语言,一起来看看吧。 为什么要用异步编程 那么为什么要用异步
简介 要想熟悉一种语言,最简单的做法就是熟悉dart提供的各种核心库。dart为我们提供了包括dart:core,dart:async,dart:math,dart:convert,dart:html和dart:io这几种常用的库。 今天给大家介绍一下dart:core中的数字和字符串的使用。 数字
简介 ES6中在引入异步编程的同时,也引入了Generators,通过yield关键词来生成对应的数据。同样的dart也有yield关键词和生成器的概念。 什么时候生成器呢?所谓生成器就是一个能够持续产生某些数据的装置,也叫做generator。 两种返回类型的generator 根据是同步生成还是
简介 Flutter的基础是widget,根据是否需要跟用户进行交互,widget则可以分为StatelessWidget和StatefulWidget。StatelessWidget只能根据传入的状态进行简单的初始化widget,如果要实现跟用户交互这种复杂的功能,则需要用到StatefulWid
简介 时间和日期是我们经常会在程序中使用到的对象。但是对时间和日期的处理因为有不同时区的原因,所以一直以来都不是很好用。就像在java中,为时间和日期修改和新增了多次API,那么作为新生的语言dart而言,会有什么不一样的地方吗? dart中关于日期和时间的两个非常重要的类是DateTime和Dur
简介 Library是dart用来组织代码的一种非常有用的方式,通过定义不同的Library,可以将非常有用的dart代码进行封装,从而提供给其他的项目使用。虽然我们可以自由使用import或者export来对library进行导入和导入。但是什么样的用法才是最合适的用法呢? 一起来看看吧。 使用p
简介 dart中的集合有三个,分别是list,set和map。dart在dart:core包中提供了对于这三种集合非常有用的方法,一起来看看吧。 List的使用 首先是list的创建,可以创建空的list或者带值的list: var emptyList =[]; var nameList = [&#
简介 dart:html包为dart提供了构建浏览器客户端的一些必须的组件,之前我们提到了HTML和DOM的操作,除了这些之外,我们在浏览器端另一个常用的操作就是使用XMLHttpRequest去做异步HTTP资源的请求,也就是AJAX请求。 dart同样提供了类似JS中XMLHttpRequest
简介 Flutter是google开发的一个跨平台的UI构建工具,flutter目前最新的版本是3.0.5。使用flutter你可以使用一套代码搭建android,IOS,web和desktop等不同平台的应用。做到一次编写到处运行的目的。 说到一次编写处处运行,大家可能会想到java。那么flut