热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

flutter图片点击跳转_Flutter系列之PlatformChannel使用详解

PS:逐渐体会到关键少数原则的重要性,接下来就是付诸实践了,另外科创50ETF明天开始限额销售,可以适当关注或入手一点。前面

18419ba0cb29960055be718cc761b1ee.png

PS:逐渐体会到关键少数原则的重要性,接下来就是付诸实践了,另外科创50ETF明天开始限额销售,可以适当关注或入手一点。

前面几篇文章介绍了 Navigator 组件、Flex 布局、图片加载、Widget 生命周期、混合开发等 Flutter 开发基础知识, 链接如下:

  • Flutter系列之Navigator使用详解

  • Flutter系列之Flex布局详解

  • Flutter系列之图片加载详解

  • Flutter系列之Widget生命周期

  • Flutter系列之混合开发Android篇

下面介绍一下 Flutter 混合开发中 Platform Channel 的使用,主要内容如下:

  1. 平台通道介绍

  2. 平台数据类型对照

  3. BasicMessageChannel

  4. MethodChannel

  5. EventChannel

平台通道介绍

Platform Channel 是一个异步消息通道,消息在发送之前会编码成二进制消息,接收到的二进制消息会解码成 Dart 值,其传递的消息类型只能是对应的解编码器支持的值,所有的解编码器都支持空消息,其 Native 与 Flutter 通信架构如下图所示:

c9873f9f27bd9c0c6da1992fa947cf95.png

Flutter 中定义了三种不同类型的 PlatformChannel,主要有三种如下:

  • BasicMessageChannel:用于数据传递;

  • MethodChannel:用于传递方法调用;

  • EventChannel:用于传递事件;

其构造方法都需指定一个通道标识、解编码器以及 BinaryMessenger,BinaryMessenger 是一个 Flutter 与平台的通信工具,用来传递二进制数据、设置对应的消息处理器等。

解编码器有两种分别是 MethodCodec 和 MessageCodec,前者对应方法后者对应消息,BasicMessageChannel 使用的是 MessageCodec,MethodChannel 和 EventChannel 使用的是 MethodCodec。

平台数据类型对照

Platform Channel 提供不同的消息解码机制,如 StandardMessageCodec 提供基本数据类型的解编码、JSONMessageCodec 支持 Json 的解编码等,在平台之间通信时都会自动转换,各平台数据类型对照如下:

1a18cc3e33daee8ed500791d0654a2fd.png

BasicMessageChannel

BasicMessageChannel 主要用来数据传递,包括二进制数据,借助 BasicMessageChannel 可以实现 MethodChannel 和 EventChannel 的功能,这里用 BasicMessageChannel 实现 Android 项目使用 Flutter 资源文件的案例,关键流程如下:

  1. Flutter 端获得图片资源对应的二进制数据,这里使用 BinaryCodec,则数据格式为 ByteData;

  2. 使用 BasicMessageChannel 发送图片对应的数据;

  3. 在 Android 端使用 ByteBuffer 接收,并将其转换成 ByteArray,然后解析成 Bitmap 显示出来。

Flutter 端关键代码如下:

1// 创建BasicMessageChannel  2_basicMessageChannel = BasicMessageChannel("com.manu.image", BinaryCodec()); 3 4// 获取assets中的图片对应的ByteData数据 5rootBundle.load('images/miao.jpg').then((value) => { 6  _sendStringMessage(value) 7}); 8 9// 发送图片数据10_sendStringMessage(ByteData byteData) async {11  await _basicMessageChannel.send(byteData);12}

Android 端关键代码如下:

1override fun configureFlutterEngine(flutterEngine: FlutterEngine) { 2    super.configureFlutterEngine(flutterEngine) 3    Log.i(tag, "configureFlutterEngine") 4    // 设置消息处理器 5    BasicMessageChannel( 6        flutterEngine.dartExecutor, "com.manu.image", BinaryCodec.INSTANCE 7    ).setMessageHandler { message, reply -> 8        Log.i(tag, "configureFlutterEngine > message:$message") 9        // 数据转换:ByteBuffer->ByteArray10        val byteBuffer = message as ByteBuffer11        imageByteArray = ByteArray(byteBuffer.capacity())12        byteBuffer.get(imageByteArray)13    }1415    // 用于设置Flutter跳转Android的方法处理器16    MethodChannel(flutterEngine.dartExecutor, channel).setMethodCallHandler { call, result ->17        Log.i(tag, "configureFlutterEngine > method:${call.method}")18        if ("startBasicMessageChannelActivity" == call.method) {19            // 携带图片数据20            BasicMessageChannelActivity.startBasicMessageChannelActivity(this,imageByteArray)21        }22    }23}2425// 显示来自Flutter assets中的图片26val imageByteArray = intent.getByteArrayExtra("key_image")27val bitmap = BitmapFactory.decodeByteArray(imageByteArray,0,imageByteArray.size)28imageView.setImageBitmap(bitmap)

另外,BasicMessageChannel 结合 BinaryCodec 是支持大内存数据块的传递的。

MethodChannel

MethodChannel 主要用来方法的传递,自然可以传递 Native 方法和 Dart 方法,即可以通过 MethodChannel 在 Flutter 中调用 Android 原生方法,在 Android 中调用 Dart 方法,互相调用都是通过 MethodChannel 的 invokeMethod 方法调用的,通信时必须使用相同的通道标识符,具体如下:

  1. Flutter调用Android方法

下面通过 MethodChannel 实现从 Flutter 跳转到 Android 原生界面 MainActivity,Android 端如下:

1/** 2 * @desc FlutterActivity 3 * @author jzman 4 */ 5val tag = AgentActivity::class.java.simpleName; 6 7class AgentActivity : FlutterActivity() { 8    val tag = AgentActivity::class.java.simpleName; 9    private val channel = "com.manu.startMainActivity"10    private var platform: MethodChannel? = null;1112    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {13        super.configureFlutterEngine(flutterEngine)14        Log.d(tag,"configureFlutterEngine")15        platform = MethodChannel(flutterEngine.dartExecutor, channel)16        // 设置方法处理器17        platform!!.setMethodCallHandler(StartMethodCallHandler(this@AgentActivity))18    }1920    companion object{21        /**22         * 重新创建NewEngineIntentBuilder才能保证生效23         */24        fun withNewEngine(): MNewEngineIntentBuilder? {25            return MNewEngineIntentBuilder(AgentActivity::class.java)26        }27    }2829    /**30     * 自定义NewEngineIntentBuilder31     */32    class MNewEngineIntentBuilder(activityClass: Class?) :33        NewEngineIntentBuilder(activityClass!!)3435    /**36     * 实现MethodCallHandler37     */38    class StartMethodCallHandler(activity:Activity) : MethodChannel.MethodCallHandler{39        private val context:Activity = activity40        override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {41            if ("startMainActivity" == call.method) {42                Log.i(tag,"arguments:"+call.arguments)43                startMainActivity(context)44                // 向Flutter回调执行结果45                result.success("success")46            } else {47                result.notImplemented()48            }49        }50    }51}

如上还可以使用 MethodChannel.Result 对象向Flutter回调执行结果,Flutter 端如下:

1/// State 2class _PageState extends State { 3  MethodChannel platform; 4 5  @override 6  void initState() { 7    super.initState(); 8    platform = new MethodChannel('com.manu.startMainActivity'); 9  }1011  @override12  Widget build(BuildContext context) {13    return Container(14      width: double.infinity,15      margin: EdgeInsets.fromLTRB(8, 8, 8, 0),16      child: RaisedButton(17        onPressed: () {18          _startMainActivity();19        },20        child: Text("Flutter to Android"),21      ),22    );23  }2425  /// 跳转到原生Activity26  void _startMainActivity() {27    platform.invokeMethod('startMainActivity', 'flutter message').then((value) {28      // 接收返回的数据29      print("value:$value");30    }).catchError((e) {31      print(e.message);32    });33  }34}

  1. Android调用Dart方法

下面通过 MethodChannel 调用 Flutter 中的 Dart 方法 getName,Android 端代码如下:

1/** 2 * @desc MainActivity 3 * @author jzman 4 */ 5class MainActivity : FlutterActivity() { 6    private val tag = MainActivity::class.java.simpleName; 7    private val channel = "com.manu.startMainActivity" 8    private var methodChannel: MethodChannel? = null 9    override fun onCreate(savedInstanceState: Bundle?) {10        super.onCreate(savedInstanceState)11        setContentView(R.layout.activity_main)1213        btnGetDart.setOnClickListener {14            getDartMethod()15        }16    }1718    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {19        super.configureFlutterEngine(flutterEngine)20        Log.i(tag,"configureFlutterEngine")21        methodChannel = MethodChannel(flutterEngine.dartExecutor,channel)22    }2324    private fun getDartMethod(){25        methodChannel?.invokeMethod("getName",null, object :MethodChannel.Result{26            override fun success(result: Any?) {27                Log.i(tag,"success: "+result.toString())28                Toast.makeText(this@MainActivity,result.toString(),Toast.LENGTH_LONG).show()29            }3031            override fun error(errorCode: String,errorMessage: String?,errorDetails: Any?) {32                Log.i(tag,"error")33            }3435            override fun notImplemented() {36                Log.i(tag,"notImplemented")37            }38        })39    }4041    companion object{42        fun startMainActivity(context: Context) {43            val intent = Intent(context, MainActivity::class.java)44            context.startActivity(intent)45        }46    }47}

Flutter 端如下:

1/// State 2class _PageState extends State { 3  MethodChannel platform; 4 5  @override 6  void initState() { 7    super.initState(); 8    platform = new MethodChannel('com.manu.startMainActivity'); 910    // 监听Android调用Flutter方法11    platform.setMethodCallHandler(platformCallHandler);12  }1314  @override15  Widget build(BuildContext context) {16    return Container();17  }18  /// FLutter Method19  Future platformCallHandler(MethodCall call) async{20    switch(call.method){21      case "getName":22        return "name from flutter";23        break;24    }25  }26}

EventChannel

EventChannel 主要用于 Flutter 到原生之间的单向调用,其使用方式类似 Android 中的广播,原生界面负责 Event 的发送,Flutter 端注册监听即可,不多说直接看代码,Android 端代码如下:

1/// Android 2class MFlutterFragment : FlutterFragment() { 3    // 这里用Fragment,Activity也一样 4    override fun configureFlutterEngine(flutterEngine: FlutterEngine) { 5        super.configureFlutterEngine(flutterEngine) 6        Log.d(tag,"configureFlutterEngine") 7        EventChannel(flutterEngine.dartExecutor,"com.manu.event").setStreamHandler(object: 8            EventChannel.StreamHandler{ 9            override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {10                Log.i(tag,"configureFlutterEngine > onListen")11                // EventSink发送事件通知12                events?.success("event message")13            }1415            override fun onCancel(arguments: Any?) {16                Log.i(tag,"configureFlutterEngine > onCancel")17            }18        })19    }2021    companion object{22        fun withNewEngine(): NewEngineFragmentBuilder? {23            return MNewEngineIntentBuilder(24                MFlutterFragment::class.java25            )26        }27    }2829    class MNewEngineIntentBuilder(activityClass: Class?) :30        NewEngineFragmentBuilder(activityClass!!)31}

Flutter 端如下:

1/// State 2class EventState extends State { 3  EventChannel _eventChannel; 4  String _stringMessage; 5  StreamSubscription _streamSubscription; 6 7  @override 8  void initState() { 9    super.initState();10    _eventChannel = EventChannel("com.manu.event");11    // 监听Event事件12    _streamSubscription =13        _eventChannel.receiveBroadcastStream().listen((event) {14      setState(() {15        _stringMessage = event;16      });17    }, onError: (error) {18      print("event error$error");19    });20  }2122  @override23  void dispose() {24    super.dispose();25    if (_streamSubscription != null) {26      _streamSubscription.cancel();27      _streamSubscription = null;28    }29  }3031  @override32  Widget build(BuildContext context) {33    return Scaffold(34        appBar: AppBar(35          title: Text("EventChannel"),36          centerTitle: true,37        ),38        body: Center(39          child: Text(_stringMessage == null ? "default" : _stringMessage),40        ));41  }42}

以上就是 Flutter 平台通道的使用,可以在公众号回复关键字【Channel】获取源码。

推荐阅读:
  • HTTPS及加密算法,看这一篇就够了
  • 自定义View实现一个日期选择器
  • Wireshark分析验证TCP协议

10cf81e5c8a997c80cff6879eddb91fc.png


推荐阅读
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • flutter图片缓存Flutter的图片缓存机制有问题(可能是我使用的版本1.12.13有问题)网络图片会默认缓存到本地,但是不管图片是不是完整的或者损坏的,导致页面在下次进入的 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • Android JSON基础,音视频开发进阶指南目录
    Array里面的对象数据是有序的,json字符串最外层是方括号的,方括号:[]解析jsonArray代码try{json字符串最外层是 ... [详细]
  • 本文讨论了Kotlin中扩展函数的一些惯用用法以及其合理性。作者认为在某些情况下,定义扩展函数没有意义,但官方的编码约定支持这种方式。文章还介绍了在类之外定义扩展函数的具体用法,并讨论了避免使用扩展函数的边缘情况。作者提出了对于扩展函数的合理性的质疑,并给出了自己的反驳。最后,文章强调了在编写Kotlin代码时可以自由地使用扩展函数的重要性。 ... [详细]
  • 如何查询zone下的表的信息
    本文介绍了如何通过TcaplusDB知识库查询zone下的表的信息。包括请求地址、GET请求参数说明、返回参数说明等内容。通过curl方法发起请求,并提供了请求示例。 ... [详细]
  • 本文介绍了如何使用JSONObiect和Gson相关方法实现json数据与kotlin对象的相互转换。首先解释了JSON的概念和数据格式,然后详细介绍了相关API,包括JSONObject和Gson的使用方法。接着讲解了如何将json格式的字符串转换为kotlin对象或List,以及如何将kotlin对象转换为json字符串。最后提到了使用Map封装json对象的特殊情况。文章还对JSON和XML进行了比较,指出了JSON的优势和缺点。 ... [详细]
  • 图像因存在错误而无法显示 ... [详细]
  • flutter插件搜索及最新依赖包查找
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了flutter插件搜索及最新依赖包查找相关的知识,希望对你有一定的参考价值。一.flutter中包和插件搜索平台 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
author-avatar
常沛威
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有