上一篇中,给大家介绍了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)
原创不易,您的点赞就是对我最大的支持,留下您的点赞吧~