当前位置: 首页 > news >正文

【移动端】Flutter 获取Android AMap实例

背景

本文的背景,是因为我在开发高德地图时,需要自定义高德比例尺位置和样式;但结果查看了AMap Flutter插件和AMap SDK源码后,发现AMap无法添加自定义MyMethodCallHandler的实现类!

why?

源码

在Flutter中,高德地图的每个地图视图都是通过AMapPlatformView类生成且管理的,源码如下

package com.amap.flutter.map;import android.content.Context;
import android.os.Bundle;
import android.view.View;import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;import com.amap.api.maps.AMap;
import com.amap.api.maps.AMapOptions;
import com.amap.api.maps.TextureMapView;
import com.amap.flutter.map.core.MapController;
import com.amap.flutter.map.overlays.marker.MarkersController;
import com.amap.flutter.map.overlays.polygon.PolygonsController;
import com.amap.flutter.map.overlays.polyline.PolylinesController;
import com.amap.flutter.map.utils.LogUtil;import java.util.HashMap;
import java.util.Map;import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.platform.PlatformView;/*** @author whm* @date 2020/10/27 5:49 PM* @mail hongming.whm@alibaba-inc.com* @since*/
public class AMapPlatformViewimplementsDefaultLifecycleObserver,ActivityPluginBinding.OnSaveInstanceStateListener,MethodChannel.MethodCallHandler,PlatformView {private static final String CLASS_NAME = "AMapPlatformView";private final MethodChannel methodChannel;private MapController mapController;private MarkersController markersController;private PolylinesController polylinesController;private PolygonsController polygonsController;private TextureMapView mapView;private boolean disposed = false;private final Map<String, MyMethodCallHandler> myMethodCallHandlerMap;AMapPlatformView(int id,Context context,BinaryMessenger binaryMessenger,LifecycleProvider lifecycleProvider,AMapOptions options) {methodChannel = new MethodChannel(binaryMessenger, "amap_flutter_map_" + id);methodChannel.setMethodCallHandler(this);myMethodCallHandlerMap = new HashMap<String, MyMethodCallHandler>(8);try {mapView = new TextureMapView(context, options);AMap amap = mapView.getMap();mapController = new MapController(methodChannel, mapView);markersController = new MarkersController(methodChannel, amap);polylinesController = new PolylinesController(methodChannel, amap);polygonsController = new PolygonsController(methodChannel, amap);initMyMethodCallHandlerMap();lifecycleProvider.getLifecycle().addObserver(this);} catch (Throwable e) {LogUtil.e(CLASS_NAME, "<init>", e);}}private void initMyMethodCallHandlerMap() {String[] methodIdArray = mapController.getRegisterMethodIdArray();if (null != methodIdArray && methodIdArray.length > 0) {for (String methodId : methodIdArray) {myMethodCallHandlerMap.put(methodId, mapController);}}methodIdArray = markersController.getRegisterMethodIdArray();if (null != methodIdArray && methodIdArray.length > 0) {for (String methodId : methodIdArray) {myMethodCallHandlerMap.put(methodId, markersController);}}methodIdArray = polylinesController.getRegisterMethodIdArray();if (null != methodIdArray && methodIdArray.length > 0) {for (String methodId : methodIdArray) {myMethodCallHandlerMap.put(methodId, polylinesController);}}methodIdArray = polygonsController.getRegisterMethodIdArray();if (null != methodIdArray && methodIdArray.length > 0) {for (String methodId : methodIdArray) {myMethodCallHandlerMap.put(methodId, polygonsController);}}}public MapController getMapController() {return mapController;}public MarkersController getMarkersController() {return markersController;}public PolylinesController getPolylinesController() {return polylinesController;}public PolygonsController getPolygonsController() {return polygonsController;}@Overridepublic void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {LogUtil.i(CLASS_NAME, "onMethodCall==>" + call.method + ", arguments==> " + call.arguments);String methodId = call.method;if (myMethodCallHandlerMap.containsKey(methodId)) {myMethodCallHandlerMap.get(methodId).doMethodCall(call, result);} else {LogUtil.w(CLASS_NAME, "onMethodCall, the methodId: " + call.method + ", not implemented");result.notImplemented();}}@Overridepublic void onCreate(@NonNull LifecycleOwner owner) {LogUtil.i(CLASS_NAME, "onCreate==>");try {if (disposed) {return;}if (null != mapView) {mapView.onCreate(null);}} catch (Throwable e) {LogUtil.e(CLASS_NAME, "onCreate", e);}}@Overridepublic void onStart(@NonNull LifecycleOwner owner) {LogUtil.i(CLASS_NAME, "onStart==>");}@Overridepublic void onResume(@NonNull LifecycleOwner owner) {LogUtil.i(CLASS_NAME, "onResume==>");try {if (disposed) {return;}if (null != mapView) {mapView.onResume();}} catch (Throwable e) {LogUtil.e(CLASS_NAME, "onResume", e);}}@Overridepublic void onPause(@NonNull LifecycleOwner owner) {LogUtil.i(CLASS_NAME, "onPause==>");try {if (disposed) {return;}mapView.onPause();} catch (Throwable e) {LogUtil.e(CLASS_NAME, "onPause", e);}}@Overridepublic void onStop(@NonNull LifecycleOwner owner) {LogUtil.i(CLASS_NAME, "onStop==>");}@Overridepublic void onDestroy(@NonNull LifecycleOwner owner) {LogUtil.i(CLASS_NAME, "onDestroy==>");try {if (disposed) {return;}destroyMapViewIfNecessary();} catch (Throwable e) {LogUtil.e(CLASS_NAME, "onDestroy", e);}}@Overridepublic void onSaveInstanceState(@NonNull Bundle bundle) {LogUtil.i(CLASS_NAME, "onDestroy==>");try {if (disposed) {return;}mapView.onSaveInstanceState(bundle);} catch (Throwable e) {LogUtil.e(CLASS_NAME, "onSaveInstanceState", e);}}@Overridepublic void onRestoreInstanceState(@Nullable Bundle bundle) {LogUtil.i(CLASS_NAME, "onDestroy==>");try {if (disposed) {return;}mapView.onCreate(bundle);} catch (Throwable e) {LogUtil.e(CLASS_NAME, "onRestoreInstanceState", e);}}@Overridepublic View getView() {LogUtil.i(CLASS_NAME, "getView==>");return mapView;}@Overridepublic void dispose() {LogUtil.i(CLASS_NAME, "dispose==>");try {if (disposed) {return;}methodChannel.setMethodCallHandler(null);destroyMapViewIfNecessary();disposed = true;} catch (Throwable e) {LogUtil.e(CLASS_NAME, "dispose", e);}}private void destroyMapViewIfNecessary() {if (mapView == null) {return;}mapView.onDestroy();}}

分析

通过上面的源码可以发现如下几点:

  1. 在它onMethodCall回调方法中,判断了方法名是否在myMethodCallHandlerMap中存在
@Overridepublic void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {LogUtil.i(CLASS_NAME, "onMethodCall==>" + call.method + ", arguments==> " + call.arguments);String methodId = call.method;if (myMethodCallHandlerMap.containsKey(methodId)) {myMethodCallHandlerMap.get(methodId).doMethodCall(call, result);} else {LogUtil.w(CLASS_NAME, "onMethodCall, the methodId: " + call.method + ", not implemented");result.notImplemented();}}
  1. myMethodCallHandlerMap 是一个final属性,这也就意味着,它在构造函数中已经实例化了,且不能更改值,只能修改内容,它通过initMyMethodCallHandlerMap注册所有的Hnadler
private final Map<String, MyMethodCallHandler> myMethodCallHandlerMap;AMapPlatformView(int id,Context context,BinaryMessenger binaryMessenger,LifecycleProvider lifecycleProvider,AMapOptions options) {methodChannel = new MethodChannel(binaryMessenger, "amap_flutter_map_" + id);methodChannel.setMethodCallHandler(this);myMethodCallHandlerMap = new HashMap<String, MyMethodCallHandler>(8);try {mapView = new TextureMapView(context, options);AMap amap = mapView.getMap();mapController = new MapController(methodChannel, mapView);markersController = new MarkersController(methodChannel, amap);polylinesController = new PolylinesController(methodChannel, amap);polygonsController = new PolygonsController(methodChannel, amap);initMyMethodCallHandlerMap();lifecycleProvider.getLifecycle().addObserver(this);} catch (Throwable e) {LogUtil.e(CLASS_NAME, "<init>", e);}
}
  1. 通过initMyMethodCallHandlerMap方法可以看出,它只注册了mapControllermarkersControllerpolylinesControllerpolygonsController四类Handler,且没有提供可以自定义注册的方法,所以我也无能为力了
private void initMyMethodCallHandlerMap() {String[] methodIdArray = mapController.getRegisterMethodIdArray();if (null != methodIdArray && methodIdArray.length > 0) {for (String methodId : methodIdArray) {myMethodCallHandlerMap.put(methodId, mapController);}}methodIdArray = markersController.getRegisterMethodIdArray();if (null != methodIdArray && methodIdArray.length > 0) {for (String methodId : methodIdArray) {myMethodCallHandlerMap.put(methodId, markersController);}}methodIdArray = polylinesController.getRegisterMethodIdArray();if (null != methodIdArray && methodIdArray.length > 0) {for (String methodId : methodIdArray) {myMethodCallHandlerMap.put(methodId, polylinesController);}}methodIdArray = polygonsController.getRegisterMethodIdArray();if (null != methodIdArray && methodIdArray.length > 0) {for (String methodId : methodIdArray) {myMethodCallHandlerMap.put(methodId, polygonsController);}}}

解决思路

1. 通过修改initMyMethodCallHandlerMap属性值(不推荐

通过上面分析可以想到,通过修改initMyMethodCallHandlerMap属性值,自定义handler,但前提时需要拿到对应的AMapPlatformView实例,通常的方法可以通过ServiceLoader来获取,但在Android中ServiceLoader是不用生效的,Android环境中必须通过PathClassLoaderDexClassLoader来加载类,具体加载方法,可以参考其他大神的博客,我这里不做过多追述,因为我不推荐

2. 通过PlatformViewsController来获取视图(推荐

推荐这个方法是因为它可以i通过mapId直接获取,且不用过多介入到内存和进程中的交互中

  1. 创建一个自定义MethodChannel
var methodChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "method_channel_id")methodChannel.setMethodCallHandler { call, result ->run {//....}}
  1. AMapPlatformView继承PlatformView,所以可以通过FlutterEngine.getPlatformViewsController().getPlatformViewById(viewId)方式获取,获取到的是TextureMapView视图,TextureMapView.getMap()可以获取AMap类,从而实现对当前地图视图进行任何操作,
class MainActivity : FlutterActivity() {var handerControllerMap = HashMap<String, IMyMethodCallHander>();override fun configureFlutterEngine(flutterEngine: FlutterEngine) {super.configureFlutterEngine(flutterEngine)IFlutterFactory.engine=flutterEngine;}
}

/*** 当前缩放级别下,地图上1像素点对应的长度,单位米。* @param call* @param result*/public void getScalePerPixel(MethodCall call, MethodChannel.Result result) {Object mapId = call.argument("mapId");if (null == call || null == mapId) {return;}try {View view = IFlutterFactory.engine.getPlatformViewsController().getPlatformViewById(Integer.parseInt(mapId.toString()));if (view != null) {result.success(((TextureMapView) view).getMap().getScalePerPixel());} else {result.error("ScaleControllerExecption", "获取比例尺数据失败!", "");}} catch (Exception e) {result.error("ScaleControllerExecption", e.getMessage(), e.getLocalizedMessage());}}
  1. viewId 其实就是mapId,可以通过AMapController.mapId获取,而AMapController可以通过AMapWidgetonMapCreated的回调方法获取
void onMapCreated(AMapController controller) {//连接自定义的MethodChannelMethodChannel _channel=MethodChannel("method_channel_id");//将mapId传给android端double? scale=await _channel.invokeMethod<double>("scale#get",<String,dynamic>{"mapId":_mapController.mapId});print('-----scale---$scale');
}

相关文章:

【移动端】Flutter 获取Android AMap实例

背景 本文的背景&#xff0c;是因为我在开发高德地图时&#xff0c;需要自定义高德比例尺位置和样式&#xff1b;但结果查看了AMap Flutter插件和AMap SDK源码后&#xff0c;发现AMap无法添加自定义MyMethodCallHandler的实现类&#xff01; why&#xff1f; 源码 在Flutte…...

什么是PLC物联网关?PLC物联网关有哪些功能?

在数字化浪潮的推动下&#xff0c;工业物联网&#xff08;IIoT&#xff09;正逐步成为推动制造业智能化转型的关键力量。而在这一变革中&#xff0c;PLC物联网关扮演着至关重要的角色。今天&#xff0c;就让我们一起走进PLC物联网关的世界&#xff0c;了解它的定义、功能&#…...

R-CNN笔记

目标检测之R-CNN论文精讲&#xff0c;RCNN_哔哩哔哩_bilibili 论文背景 在该论文提出之前&#xff0c;主流的目标检测思路是&#xff1a; 将一幅图片划分成很多个区域&#xff0c;单独提取出来 对于每个区域使用传统的特征提取方法提取 提取结束后可以使用以为特征向量表示 可以…...

uni-app从零开始快速入门

教程介绍 跨端框架uni-app作为新起之秀&#xff0c;在不到两年的时间内&#xff0c;迅速被广大开发者青睐和推崇&#xff0c;得益于它颠覆性的优势“快”&#xff0c;快到可以节省7套代码。本课程由uni-app开发者团队成员亲授&#xff0c;带领大家无障碍快速掌握完整的uni-app…...

Springboot集成jersey打包jar找不到class处理

环境 java17 springboot 3.x 如题&#xff0c;简单来说&#xff0c;jersey官方希望用户通过 register 的方式&#xff0c;将所有的资源类注册到jersey中&#xff0c;但是&#xff0c;一般开发中&#xff0c;可能定义了N个Resource类&#xff0c;一个一个的加入&#xff0c;太…...

基于springboot和vue的旅游资源网站的设计与实现

环境以及简介 基于vue, springboot旅游资源网站的设计与实现&#xff0c;Java项目&#xff0c;SpringBoot项目&#xff0c;含开发文档&#xff0c;源码&#xff0c;数据库以及ppt 环境配置&#xff1a; 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xf…...

Python编程异步爬虫——协程的基本原理

Python编程之异步爬虫 协程的基本原理 要实现异步机制的爬虫&#xff0c;自然和协程脱不了关系。 案例引入 先看一个案例网站&#xff0c;地址为https://www.httpbin.org/delay/5&#xff0c;访问这个链接需要先等5秒钟才能得到结果&#xff0c;这是因为服务器强制等待5秒时…...

基于springboot+vue的旅游推荐系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…...

Debezium日常分享系列之:Debezium2.5稳定版本之Monitoring

Debezium日常分享系列之&#xff1a;Debezium2.5稳定版本之Monitoring 一、Snapshot metrics二、Streaming metrics三、Schema history metrics Debezium系列之&#xff1a;安装jmx导出器监控debezium指标 除了 Zookeeper、Kafka 和 Kafka Connect 提供的对 JMX 指标的内置支持…...

GuLi商城-商品服务-API-三级分类-网关统一配置跨域

参考文档&#xff1a; https://tangzhi.blog.csdn.net/article/details/126754515 https://github.com/OYCodeSite/gulimall-learning/blob/master/docs/%E8%B0%B7%E7%B2%92%E5%95%86%E5%9F%8E%E2%80%94%E5%88%86%E5%B8%83%E5%BC%8F%E5%9F%BA%E7%A1%80.md 谷粒商城-day04-完…...

【ai技术】(4):在树莓派上,使用qwen0.5b大模型+chatgptweb,搭建本地大模型聊天环境,速度飞快,非常不错!

1&#xff0c;视频地址 https://www.bilibili.com/video/BV1VK421i7CZ/ 【ai技术】&#xff08;4&#xff09;&#xff1a;在树莓派4上&#xff0c;使用ollama部署qwen0.5b大模型chatgptweb前端界面&#xff0c;搭建本地大模型聊天工具&#xff0c;速度飞快 2&#xff0c;下载…...

深入理解PHP+Redis实现分布式锁的相关问题

概念 PHP使用分布式锁&#xff0c;受语言本身的限制&#xff0c;有一些局限性。 通俗理解单机锁问题&#xff1a;自家的锁锁自家的门&#xff0c;只能保证自家的事&#xff0c;管不了别人家不锁门引发的问题&#xff0c;于是有了分布式锁。分布式锁概念&#xff1a;是针对多个…...

perl:获取同花顺数据--业绩预告

perldoc LWP::UserAgent 如果没有安装&#xff0c;则安装模块&#xff0c;运行 cpanm LWP::UserAgent 。 编写 get_yjyg_10jqka.pl 如下 #!/usr/bin/perl # perl 获取同花顺数据--业绩预告 use LWP::UserAgent; use Encode qw(decode encode); use POSIX; use Data::Dump…...

如何对比引用传参和值传参两者的效率

以值作为参数或者返回值类型&#xff0c;在传参和返回期间&#xff0c;函数不会直接传递实参或者将变量本身直接返回&#xff0c;而是传递实参或者返回变量的一份临时的拷贝&#xff0c;因此用值作为参数或者返回值类型&#xff0c;效率是非常低下的&#xff0c;尤其是当参数或…...

探索软件工程:构建可靠、高效的数字世界

软件工程是一门涵盖了设计、开发、测试、维护和管理软件的学科&#xff0c;它在如今数字化时代的发展中扮演着至关重要的角色。随着科技的不断进步和社会的不断变迁&#xff0c;软件工程的意义也愈发凸显。本文将探索软件工程的重要性、原则和实践&#xff0c;以及其对当今社会…...

超越肉眼:深入计算机视觉的奇妙之旅

揭秘计算机视觉的奥秘&#xff1a;从基础到前沿的探索之旅 引言&#xff1a;一、计算机视觉的基础1. 图像处理基础2. 特征提取与描述3. 基本模式识别 二、机器学习在计算机视觉中的应用1. 深度学习革命2. 迁移学习与多任务学习3. 强化学习与主动学习4. 无监督学习和自监督学习 …...

mac 安装 nvm 【真解决问题】

前提 没有node环境已有git 下载 我用的gitee极速下载 git clone https://gitee.com/mirrors/nvm.git ~/.nvm && cd ~/.nvm && git checkout git describe --abbrev0 --tags配置 1. 配置变量 在用户的目录下新增文件 .zshrc export NVM_DIR"$HOME/…...

【Godot 3.5控件】用TextureProgress制作血条

说明 本文写自2022年11月13日-14日&#xff0c;内容基于Godot3.5。后续可能会进行向4.2版本的转化。 概述 之前基于ProgressBar创建过血条组件。它主要是基于修改StyleBoxFlat&#xff0c;好处是它几乎可以算是矢量的&#xff0c;体积小&#xff0c;所有东西都是样式信息&am…...

第十届蓝桥杯大赛个人赛省赛(软件类)真题- CC++ 研究生组

第十届蓝桥杯大赛个人赛省赛&#xff08;软件类&#xff09;真题- C&C 研究生组-立方和 第十届蓝桥杯大赛个人赛省赛&#xff08;软件类&#xff09;真题- C&C 研究生组-字串数字 第十届蓝桥杯大赛个人赛省赛&#xff08;软件类&#xff09;真题- C&C 研究生组-质数…...

Linux:Gitlab:16.9.2 创建用户及项目仓库基础操作(2)

我在上一章介绍了基本的搭建以及邮箱配置 Linux&#xff1a;Gitlab:16.9.2 (rpm包) 部署及基础操作&#xff08;1&#xff09;-CSDN博客https://blog.csdn.net/w14768855/article/details/136821311?spm1001.2014.3001.5501 本章介绍一下用户的创建&#xff0c;组内设置用户&…...

谷歌浏览器插件

项目中有时候会用到插件 sync-cookie-extension1.0.0&#xff1a;开发环境同步测试 cookie 至 localhost&#xff0c;便于本地请求服务携带 cookie 参考地址&#xff1a;https://juejin.cn/post/7139354571712757767 里面有源码下载下来&#xff0c;加在到扩展即可使用FeHelp…...

Java 语言特性(面试系列2)

一、SQL 基础 1. 复杂查询 &#xff08;1&#xff09;连接查询&#xff08;JOIN&#xff09; 内连接&#xff08;INNER JOIN&#xff09;&#xff1a;返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中&#xff0c;Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染&#xff08;即CPU被阻塞&#xff09;&#xff0c;这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&…...

23-Oracle 23 ai 区块链表(Blockchain Table)

小伙伴有没有在金融强合规的领域中遇见&#xff0c;必须要保持数据不可变&#xff0c;管理员都无法修改和留痕的要求。比如医疗的电子病历中&#xff0c;影像检查检验结果不可篡改行的&#xff0c;药品追溯过程中数据只可插入无法删除的特性需求&#xff1b;登录日志、修改日志…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序

一、开发准备 ​​环境搭建​​&#xff1a; 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 ​​项目创建​​&#xff1a; File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

生成 Git SSH 证书

&#x1f511; 1. ​​生成 SSH 密钥对​​ 在终端&#xff08;Windows 使用 Git Bash&#xff0c;Mac/Linux 使用 Terminal&#xff09;执行命令&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ​​参数说明​​&#xff1a; -t rsa&#x…...

Android15默认授权浮窗权限

我们经常有那种需求&#xff0c;客户需要定制的apk集成在ROM中&#xff0c;并且默认授予其【显示在其他应用的上层】权限&#xff0c;也就是我们常说的浮窗权限&#xff0c;那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

10-Oracle 23 ai Vector Search 概述和参数

一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI&#xff0c;使用客户端或是内部自己搭建集成大模型的终端&#xff0c;加速与大型语言模型&#xff08;LLM&#xff09;的结合&#xff0c;同时使用检索增强生成&#xff08;Retrieval Augmented Generation &#…...

JVM 内存结构 详解

内存结构 运行时数据区&#xff1a; Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器&#xff1a; ​ 线程私有&#xff0c;程序控制流的指示器&#xff0c;分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 ​ 每个线程都有一个程序计数…...

Ubuntu Cursor升级成v1.0

0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开&#xff0c;快捷键也不好用&#xff0c;当看到 Cursor 升级后&#xff0c;还是蛮高兴的 1. 下载 Cursor 下载地址&#xff1a;https://www.cursor.com/cn/downloads 点击下载 Linux (x64) &#xff0c;…...