首先先描述一下需求
这里假如有这样一个煮饭流程(每一个流程安卓端都会推送一次数据),分为准备煮饭,煮饭开始(预计多少秒之后完成),煮饭完成,取饭,洗锅。flutter在每一次接收不同推送分别弹出更新不同的窗口。用于提示用户当前的煮饭已经进行到哪个流程。
下面为安卓端推送的数据格式(注意flutter接收到的数据是一个Sting格式的数据,因此需要把数据格式进行转化)
第一步推送的数据为 data:{'code':'response'},// 准备煮饭
第二部推送的数据为 data:{'code':'start',time:'123456789'},// 煮饭开始 time为预计多少秒之后完成 是一个秒为单位的时间戳
第三部 data:{'code':'cookFinish'},//煮饭完成
第四部 data:{'code':'takeRice'}:在煮饭完成的时候 可点击取饭。然后进入取饭状态
第五步data:{'code':'clean'}:取饭完成,洗锅 流程结束
不同的阶段,flutter需要更新对应的状态视图。显示对应的煮饭状态
以下是实现的具体逻辑代码 首先在Cop这个类的顶部放一个全局的变量: ctx = null 然后在ConfirmDialog这个组件的生命周期initState里把当前页面的上下文赋值给ctx,用来判断当前页面是否已经打开了ConfirmDialog,可以防止basicMessageChannel.setMessageHandler被执行多次而出现重复弹窗的问题。然后再把basicMessageChannel.setMessageHandler写在弹窗页面里,相当于把任务再交给子组件。
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';// 先导包
import 'dart:convert' as convert; //把string转化为json格式的包
var ctx;
class Cop extends StatefulWidget {
Cop({Key key}) : super(key: key);
@override
_Cop createState() => _CopState();
}
class _CopState extends State<Cop> {
static const basicMessageChannel = const BasicMessageChannel('Cabinet_BasicMessageChannel', StringCodec());
void messageHandler(){
//在父页面: 建议把接收推送消息的方法(basicMessageChannel.setMessageHandler)写在一个方法 然后在生命周期初始化话的时候调用,然后在弹窗被打开的时候,顺便把这个方法传过去, 以便在弹窗关闭的时候 重新激活这个方法。不然当弹窗一旦被关闭的时候,父页面的basicMessageChannel.setMessageHandler会被销毁,就会导致再也监听不到安卓的消息推送(这一点非常重要)
basicMessageChannel.setMessageHandler((data) => Future<String>(() { //
Map json = convert.jsonDecode(data); //从安卓推送过来的数据 是一个String类型的数据 必须转为对象
if( ctx == null ){ //防止被重复弹窗
//现在变成这样 父页面弹窗之后 监听交给子页面去处理 子页面接收数据之后 更新视图
ConfirmDialog(json,this.messageHandler);
}
}));
}
@override
void initState() {
// TODO: implement initState
super.initState();
this.messageHandler();
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
}
@override
Widget build(BuildContext context) {
return Text('')
}
}
class ConfirmDialog extends StatefulWidget {
Map json;
Function fn;
ConfirmDialog(this.json,this.fn,{Key key}) : super(key: key);
@override
_ConfirmDialogState createState() => _ConfirmDialogState(json:this.json,fn:this.fn);
}
class _ConfirmDialogState extends State<ConfirmDialog> {
Map msgData;
_ConfirmDialogState({this.json,this.fn});
@override
void initState() {
// TODO: implement initState
super.initState();
ctx = contex; // 把当前上下文context赋值给ctx
basicMessageChannel.setMessageHandler((data) => Future<String>(() { //
Map json = convert.jsonDecode(data);
//这里接收数据 直接根据数据改变视图
setState({
this.msgData = data;
})
}));
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
this.fn();// 关闭的时候 重新调用父页面的监听,以便继续监听推送 需要注意 :子页面关闭的context 其实和父页面是同一个context(这点很重要)
ctx = null; // 页面销毁的时候 记得把ctx设置成null 以便下一次弹窗
}
@override
Widget build(BuildContext context) {
return Material(
type: MaterialType.transparency,
child: Center(
child:Text('')
)
);
}
}