Kotlin+JetpackCompose接入高德地图
Android原生开发快速接入高德地图,本文简单就显示地图和获取POI搜索数据进行简单的讲解。
·
一.引言
Android原生开发快速接入高德地图,本文简单就显示地图和获取POI搜索数据进行简单的讲解。如果你觉得本文对你有帮助,来一波点赞关注赞赏,谢谢!
二.接入流程
1.在官网注册,获取key
获取Key-创建工程-开发指南-Android 地图SDK | 高德地图API
2.从官网下载资源并在项目中导入

3.项目配置
在AndroidManifest.xml文件中配置(将key替换为你从官网获取的key值)
<meta-data android:name="com.amap.api.v2.apikey" android:value="key">
</meta-data>
设置权限
<!--允许访问网络,必选权限-->
<uses-permission android:name="android.permission.INTERNET" />
<!--允许获取粗略位置,若用GPS实现定位小蓝点功能则必选-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!--用于访问GPS定位-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!--用于提高GPS定位速度-->
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<!--允许获取网络状态,用于网络定位,若无gps但仍需实现定位小蓝点功能则此权限必选-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--允许获取wifi网络信息,用于网络定位,若无gps但仍需实现定位小蓝点功能则此权限必选-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!--允许获取wifi状态改变,用于网络定位,若无gps但仍需实现定位小蓝点功能则此权限必选-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!--允许写入扩展存储,用于数据缓存,若无此权限则写到私有目录-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission" />
4.代码实现
class MainActivity : ComponentActivity(), PoiSearch.OnPoiSearchListener, LocationSource, AMap.OnMyLocationChangeListener {
// 定义定位权限请求的代码
private val LOCATION_PERMISSION_REQUEST_CODE = 1001
private lateinit var poiSearch: PoiSearch
private var poiResult: PoiResult? = null
private var poiItems: List<PoiItem>? = null
private var isLoading by mutableStateOf(false)
private var poiDetails by mutableStateOf<List<PoiItem>>(emptyList())
// 地图视图和 AMap 相关引用
private lateinit var mapView: MapView
private lateinit var aMap: AMap
private var locationMarker: Marker? = null
private var locationClient: AMapLocationClient? = null
private lateinit var locationOption: AMapLocationClientOption
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 设置高德地图的 API Key
setApiKey("************************")
// 检查定位权限,如果未授予则请求权限
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), LOCATION_PERMISSION_REQUEST_CODE)
} else {
// 如果权限已授予,初始化地图和定位功能
initializeMapAndLocation()
}
// Jetpack Compose 的UI内容
setContent {
// 显示搜索 POI 的界面
PoiSearchScreen()
}
}
// 初始化地图和定位功能
private fun initializeMapAndLocation() {
mapView = MapView(this)
mapView.onCreate(null) // 必须在生命周期内调用
aMap = mapView.map
setupLocationStyle()
aMap.setLocationSource(this)
aMap.isMyLocationEnabled = true
aMap.setOnMyLocationChangeListener(this)
}
// 搜索 POI 的界面
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun PoiSearchScreen() {
Box(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
) {
Column {
Button(
onClick = {
isLoading = true
performNearbyPoiSearch()// 执行 POI 搜索
},
modifier = Modifier.fillMaxWidth().zIndex(2f)
) {
Text("搜索附近的 POI")
}
Spacer(modifier = Modifier.height(16.dp))
if (isLoading) {
CircularProgressIndicator()
}
LazyColumn(modifier = Modifier.fillMaxWidth()) {
items(poiDetails) { poiItem ->
PoiItemView(poiItem) { latLng ->
// 在点击 POI 时,更新地图标记的位置并聚焦
updateMapWithPoiLocation(latLng)
} // 显示每个 POI 的详情
}
}
// 地图视图的容器
AndroidView(factory = { mapView }) {
it.onResume() // 必须确保地图生命周期同步
}
}
}
}
// 定义POI条目的UI
@Composable
fun PoiItemView(poiItem: PoiItem,onClick: (LatLng) -> Unit) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.clickable {
val latLng = LatLng(poiItem.latLonPoint.latitude, poiItem.latLonPoint.longitude)
onClick(latLng) // 点击时传递 POI 的坐标
}
) {
val imageUrl = poiItem.photos?.getOrNull(0)?.url // 获取第一个照片
if (imageUrl != null) {
Image(
painter = rememberAsyncImagePainter(imageUrl),
contentDescription = "POI 图片",
modifier = Modifier.size(80.dp),
contentScale = ContentScale.Crop
)
}
Spacer(modifier = Modifier.width(8.dp))
Column {
Text(poiItem.title, style = MaterialTheme.typography.bodyMedium)
Text(poiItem.snippet, style = MaterialTheme.typography.bodyMedium)
Text(poiItem.tel, style = MaterialTheme.typography.bodyMedium)
}
}
}
// 设置蓝点样式
private fun setupLocationStyle() {
val myLocationStyle = MyLocationStyle()
.myLocationType(MyLocationStyle.LOCATION_TYPE_FOLLOW) // 设置蓝点跟随模式
.interval(2000) // 每2秒更新一次位置
.strokeColor(R.color.purple_200) // 蓝点精度圈边框颜色
.radiusFillColor(R.color.purple_500) // 蓝点精度圈填充颜色
.strokeWidth(2f) // 精度圈边框宽度
aMap.setMyLocationStyle(myLocationStyle)
aMap.uiSettings.isMyLocationButtonEnabled = true // 显示定位按钮
}
// 执行附近 POI 搜索
private fun performNearbyPoiSearch() {
val location = locationMarker?.position
if (location != null) {
val latLonPoint = LatLonPoint(location.latitude, location.longitude)
//keyWord表示搜索字符串,
//第二个参数表示POI搜索类型,二者选填其一,选用POI搜索类型时建议填写类型代码,码表可以参考下方(而非文字)
//cityCode表示POI搜索区域,可以是城市编码也可以是城市名称,也可以传空字符串,空字符串代表全国在全国范围内进行搜索
val query = PoiSearch.Query("自习室", "", "")
query.extensions = "all"
query.pageSize = 3
query.pageNum = 0
poiSearch = PoiSearch(this, query)
poiSearch.bound = PoiSearch.SearchBound(latLonPoint, 10000)
poiSearch.setOnPoiSearchListener(this)
poiSearch.searchPOIAsyn()
} else {
isLoading = false
poiDetails = emptyList()
}
}
// POI 搜索结果回调
override fun onPoiSearched(result: PoiResult?, rCode: Int) {
isLoading = false
if (rCode == 1000 && result != null) {
poiResult = result
poiItems = result.pois
// 更新POI列表
poiDetails = poiItems ?: emptyList()
// 清除旧的地图标记
aMap.clear()
// 为每个 POI 添加标记
poiItems?.forEach { poi ->
val latLng = LatLng(poi.latLonPoint.latitude, poi.latLonPoint.longitude)
aMap.addMarker(MarkerOptions().position(latLng).title(poi.title))
}
} else {
poiDetails = emptyList()
}
}
// 定位激活时的回调
override fun activate(listener: LocationSource.OnLocationChangedListener?) {
locationClient = AMapLocationClient(applicationContext)
locationOption = AMapLocationClientOption().apply {
locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy
interval = 2000
}
locationClient?.setLocationListener { location ->
listener?.onLocationChanged(location)
val latLng = LatLng(location.latitude, location.longitude)
if (locationMarker == null) {
locationMarker = aMap.addMarker(MarkerOptions().position(latLng).title("当前位置"))
} else {
locationMarker?.position = latLng
}
}
locationClient?.setLocationOption(locationOption)
locationClient?.startLocation()
}
// 定位停用时的回调
override fun deactivate() {
locationClient?.stopLocation()
locationClient?.onDestroy()
locationClient = null
}
// 我的位置变化时的回调(可选实现)
override fun onMyLocationChange(location: Location?) {}
// 单个 POI 条目搜索回调(此处暂未使用)
override fun onPoiItemSearched(poiItem: PoiItem?, rCode: Int) {
}
// 更新地图标记位置并聚焦
private fun updateMapWithPoiLocation(latLng: LatLng) {
aMap.clear() // 清除旧的标记
aMap.addMarker(MarkerOptions().position(latLng).title("当前位置")) // 添加新的标记
aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15f)) // 聚焦到该位置,缩放级别为15
}
}
5.注意
query.setExtensions("all")
这是关键,因为搜索SDK自7.6.0开始增加了setExtension() 方法控制深度信息,扩展字段 base表示只返回基础数据,all表示所有数据,默认为base,可以通过query设置all,获取到完整的地址信息。
6.效果展示图
点击item,地图会更新。如果拓展需要其他Poiitem类型,请查看官方文档

三.结尾
以上就是我在Compose中对高德地图的简单接入。你可以在此基础上进行拓展,一定要注意处理好生命周期,否则会出错。如果你有任何疑问,可以在评论区讨论。
更多推荐



所有评论(0)