关于flutter和安卓通信踩坑(注意事项)

326 阅读3分钟

首先先描述一下需求 这里假如有这样一个煮饭流程(每一个流程安卓端都会推送一次数据),分为准备煮饭,煮饭开始(预计多少秒之后完成),煮饭完成,取饭,洗锅。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('')
         )
     );
  }
}