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

山东大学创新实训项目个人博客——第三篇

本周是项目开始开发的第四周,主要完成了导航界面中高德API的集成工作。

在 build.gradle.kts中配置依赖:

//build.gradle.kts(Module:app) implementation("com.amap.api:3dmap-location-search:latest.integration")

在manifest中配置相关权限、设置好API key、声明定位服务:

<!-- 网络权限 --> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- 定位权限 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <meta-data android:name="com.amap.api.v2.apikey" android:value="在高德控制台中创建的api-key" /> <!-- 在application标签下--> <service android:name="com.amap.api.location.APSService" />

将高德官方下载的SDK内的so文件拷贝到与项目src目录同级的libs目录下,发现x86_64文件夹为空,说明高德官方已经不再支持在x86架构cpu上运行了,也就意味着Android Studio内置的基于x86架构的虚拟机无法运行高德SDK,也就意味着以后的开发不得不使用真机测试了:

复制完so文件后在build.gradle.kts中配置,确保原生库在不同CPU架构设备上正常运行:

defaultConfig { applicationId = "com.example.wenkang" minSdk = 29 targetSdk = 36 versionCode = 1 versionName = "1.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" ndk { abiFilters += listOf("armeabi-v7a", "arm64-v8a", "x86_64") } }

在MainActivity的onCreate中配置如下参数,告诉高德SDK我们已经得到了用户的许可,才能开始使用高德SDK(这里硬编码为true,实际上应该询问用户后再设置为true):

// 地图SDK隐私合规 MapsInitializer.updatePrivacyShow(this, true, true) MapsInitializer.updatePrivacyAgree(this, true) // 定位SDK隐私合规 AMapLocationClient.updatePrivacyShow(this, true, true) AMapLocationClient.updatePrivacyAgree(this, true)

将之前NavigationScreen中从ConsultationScreen复制过来的代码一并删除,整个界面为一个Column分为上中下三个部分,上部分占百分之五十,为地图部分,其余两部分占百分之二十五,分别是查询出来的医院列表(横向排布)和列表中选中的医院的详情。

这里主要介绍地图部分;初始化MapView:

val mapViewState = remember { MapView(context).apply { setMapView(this) } }

由于MapView是传统的Android View,需要手动进行生命周期管理:

DisposableEffect(Unit) { mapViewState.onCreate(null) // 创建地图 mapViewState.onResume() // 恢复地图 onDispose { mapViewState.onPause() // 暂停地图 mapViewState.onDestroy() // 销毁地图 } }

将其嵌入Compose中,其中mapView.map 获取核心的 AMap 对象,后续所有地图操作都基于它:

AndroidView( factory = { mapViewState }, modifier = Modifier.fillMaxSize() ) { mapView -> val aMap = mapView.map // 获取 AMap 对象 setAMap(aMap) // 设置地图点击事件 aMap.setOnMarkerClickListener { marker -> val hospital = markerHospitalMap[marker] hospital?.let { setSelectedHospital(it) } true } }

以上是将高德地图MapView嵌入Compose的步骤,用户在同意了权限后,应该开启定位服务并将地图的定位中心切换到用户,搜索周围的医院。

在NavigationViewModel中写下获取用户定位方法,大致的流程就是检查权限后进行定位,如果定位不成功则使用默认定位,这里由于项目要求,定位成功后立刻调用了使用POI搜索医院的方法:

fun getCurrentLocation(context: Context? = null) { context?.let { // 先检查定位权限,权限验证不通过则使用默认位置 //使用try catch包裹,定位失败也使用默认位置 try { locationClient = AMapLocationClient(it) val option = AMapLocationClientOption().apply { locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy isOnceLocation = true isNeedAddress = true // 获取详细地址信息 httpTimeOut = 30000 // 设置超时时间30秒 isGpsFirst = true // GPS优先 } locationClient?.setLocationOption(option) locationClient?.setLocationListener(object : AMapLocationListener { override fun onLocationChanged(location: AMapLocation) { if (location.errorCode == 0) { val loc = Location("AMap").apply { latitude = location.latitude longitude = location.longitude accuracy = location.accuracy time = location.time } _currentLocation.value = loc // 定位成功后搜索附近医院 searchNearbyHospitals(context, location.latitude, location.longitude) } else { // 定位失败,使用默认位置 val defaultLocation = Location("Default").apply { latitude = 39.916345 longitude = 116.407174 } _currentLocation.value = defaultLocation searchNearbyHospitals(context, defaultLocation.latitude, defaultLocation.longitude) } } }) locationClient?.startLocation() } catch (e: Exception) { e.printStackTrace() // 发生异常时使用默认位置 val defaultLocation = Location("Default").apply { latitude = 39.916345 longitude = 116.407174 } _currentLocation.value = defaultLocation searchNearbyHospitals(context, defaultLocation.latitude, defaultLocation.longitude) } } }

而在UI层,如果ViewModel成功获取到了用户定位,UI层监听到后就会进行更新:

LaunchedEffect(currentLocation) { currentLocation?.let { location -> val latLng = LatLng(location.latitude, location.longitude) // 移动相机到用户位置 aMap?.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15f)) // 添加蓝色标记 aMap?.addMarker( MarkerOptions() .position(latLng) .title("我的位置") .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE)) ) } }

以上就是从用户打开界面、定位到用户位置到地图重定位并使用蓝色进行标记的全过程。POI搜索功能的实现大致相同,同样是定位到用户位置后,根据用户的位置去查询附近的医院并返回到hospitals中,UI层监听到hospitals发生改变后即在地图上使用红色进行标记,并将hospitals列表展示在下方的横向列表中,列表的selected属性发生变化时切换地图的聚焦中点,也就实现了追踪不同医院的效果:

// 搜索附近医院(使用高德 POI 搜索) fun searchNearbyHospitals(context: Context? = null, latitude: Double = 39.916345, longitude: Double = 116.407174) { if (context == null) return try { // 查询条件:关键词"医院",搜索类型为综合医院 val query = PoiSearch.Query("三甲医院", "", "") // 设置搜索范围 val searchBound = PoiSearch.SearchBound( LatLonPoint(latitude, longitude), 100000 // 半径 ) query.pageSize = 20 // 创建搜索实例 val poiSearch = PoiSearch(context, query) poiSearch.bound = searchBound poiSearch.setOnPoiSearchListener(object : PoiSearch.OnPoiSearchListener { override fun onPoiSearched(result: PoiResult?, code: Int) { if (code == 1000 && result != null && result.pois != null) { val hospitals = result.pois.map { poi -> HospitalWithLocation( name = poi.title ?: "未知医院", address = poi.snippet ?: poi.adName ?: "地址未知", department = "综合医院", level = "三级甲等", rating = 4.5f, // 默认评分 latitude = poi.latLonPoint?.latitude ?: latitude, longitude = poi.latLonPoint?.longitude ?: longitude ) } _hospitals.value = hospitals } else { // 搜索失败时使用预设模拟数据作为保底 loadMockHospitals() } } override fun onPoiItemSearched(item: PoiItem?, code: Int) {} }) poiSearch.searchPOIAsyn() } catch (e: Exception) { e.printStackTrace() loadMockHospitals() } }
// 监听医院列表变化,更新地图标记 LaunchedEffect(hospitals) { // 清除旧标记 markers.forEach { it.remove() } setMarkers(emptyList()) setMarkerHospitalMap(emptyMap()) // 添加新标记 val newMarkers = mutableListOf<Marker>() val newMarkerHospitalMap = mutableMapOf<Marker, HospitalWithLocation>() hospitals.forEach { val latLng = LatLng(it.latitude, it.longitude) val marker = aMap?.addMarker( MarkerOptions() .position(latLng) .title(it.name) .snippet(it.address) .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED)) ) marker?.let {m -> newMarkers.add(m) newMarkerHospitalMap[m] = it } } setMarkers(newMarkers) setMarkerHospitalMap(newMarkerHospitalMap) }
LazyRow( modifier = Modifier.fillMaxWidth(), contentPadding = PaddingValues(horizontal = 16.dp) ) { items(hospitals) { HospitalCard( hospital = it, isSelected = selectedHospital?.name == it.name, onSelect = { setSelectedHospital(it) // 点击医院时,地图移动到该医院位置 val latLng = LatLng(it.latitude, it.longitude) aMap?.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15f)) } ) } }

以上就是本项目集成高德SDK的过程,用于定位用户并给用户推荐附近的三甲医院。不过后端的同学跟我说医院的推荐将由他们来完成,他们会提供一个根据数据库推荐四家附近医院并返回医院更加详细信息的方法,不需要调用高德POI搜索办法了,后面我也会根据具体的后端实现进行修改。目前实现的效果如下:

接下来的工作是完成注册界面(拖了两周了),优化主界面的布局(搬到真机上运行发现界面的排布还是有些问题),以及完成导航阶段的前一个阶段——问诊阶段,这部分后端的api已经实现,我可以进行更具体的适配了,比如实现流式输出等等。

http://www.jsqmd.com/news/709942/

相关文章:

  • VinXiangQi完整指南:3步实现AI象棋对战,新手也能轻松上手
  • 仅剩最后7家医院开放AI联合建模接口!手把手用Pydicom+SimpleITK+nnUNet构建多中心联邦学习诊断平台
  • 5分钟打造专属AI歌手:用Retrieval-based-Voice-Conversion-WebUI实现零门槛语音克隆
  • ubuntu CT文件查看器---
  • VS Code远程容器开发突然变卡?92%的企业忽略的.devcontainer/devcontainer.lock缓存陷阱(附自动清理+增量构建脚本)
  • 终极HTML转Word指南:3分钟掌握html-to-docx实现完美文档转换 [特殊字符]✨
  • 数据清洗全流程指南:从诊断到自动化实践
  • Day06-06.图像相关知识介绍
  • 【企业级Dev Container架构白皮书】:基于Kubernetes+OCI标准的可复现、可审计、可灰度的容器开发环境落地规范
  • 从零开始部署gemma4
  • 5分钟掌握SRWE:解锁窗口分辨率自定义的终极工具
  • G-Helper:释放华硕笔记本隐藏性能的轻量级神器
  • Untrunc视频修复终极指南:10分钟拯救你的损坏视频文件
  • 终极视频对比分析工具:5分钟快速上手开源神器
  • 3分钟掌握GEMMA:让复杂遗传数据分析变得简单的终极指南
  • 2026年宁波短视频代运营与GEO搜索优化:中小企业同城竞争突破指南 - 精选优质企业推荐官
  • AI智能体如何30分钟构建全栈酒店预订平台:技术架构与协作机制解析
  • 3分钟揪出Windows热键冲突的“元凶“:Hotkey Detective使用全攻略
  • 简单理解:DLL 库 和 SO 库
  • DLSS Swapper革命性工具:智能游戏画质提升的一键式解决方案
  • 智能自动化助手:3个秘诀让你的Android设备更高效
  • 3分钟搭建零配置静态服务器:http-server让本地开发效率翻倍 [特殊字符]
  • 2026有实力且性价比高的工业窑炉厂家推荐哪家?破解粉体干燥能耗居高不下困局 - 品牌种草官
  • MaxKB4j:Java原生的企业级RAG与智能体引擎设计与实战
  • 2026最新中医执医考试课程选择——为何阿虎课程好 - 医考机构品牌测评专家
  • 多模态模型评估框架AdaptMMBench解析与应用
  • 皮肤管理店收银系统哪个靠谱?行业力荐品牌
  • 全面掌握ezdxf:Python处理DXF文件的终极指南
  • 工业点云必须跨过的三道生死关(噪声鲁棒性|多视角一致性|亚毫米级重复精度):一份被17家制造企业联合采纳的校准白皮书
  • 2026年宁波GEO优化与短视频引流:5大服务商实战对比与中小企业选购攻略 - 精选优质企业推荐官