地图集成:Google Maps SDK配置、MapView与SupportMapFragment、在地图上显示位置
地图功能,几乎是现代位置感知应用的标配。你想想看,光知道经纬度坐标,用户根本没啥概念。但把那个点往地图上一标,周围有什么、怎么过去,一目了然。这一章,我们就来啃下 Google Maps 集成这块硬骨头。
说实话,Google Maps SDK 的配置,在 Android 开发里算是比较折腾的一环。我早期做项目时,光配个 API Key 就折腾了半天,后来发现是 SHA-1 指纹填错了。嗯,这些坑咱们都得提前避开。
Google Maps SDK 配置
配置分两步走:先搞定 Google Cloud Console,再搞定 Android 项目。
1. 获取 API Key
你得去 Google Cloud Console 创建一个项目,然后启用 Maps SDK for Android。接着创建凭据,生成一个 API Key。
这里有个关键点:一定要限制 API Key 的使用范围。我见过有人直接把没限制的 Key 硬编码到 App 里,结果被别人盗刷,一天跑了十几万次请求,账单直接爆炸。
2. 在 Android 项目中配置
首先,在 build.gradle(Module 级别)里添加依赖:
dependencies {
implementation 'com.google.android.gms:play-services-maps:18.2.0'
// 如果你还需要定位功能
implementation 'com.google.android.gms:play-services-location:21.0.2'
}
然后,把 API Key 放到 AndroidManifest.xml 的 <application> 标签内:
<meta-data
android:name="com.google.android.googlemaps.API_KEY"
android:value="你的API_KEY" />
我个人习惯把 API Key 放在 local.properties 或者 gradle.properties 里,通过 BuildConfig 引用。这样不会把 Key 提交到 Git 仓库,安全一些。
MapView 与 SupportMapFragment
Google Maps 提供了两种方式来展示地图:MapView 和 SupportMapFragment。说白了,一个是用在自定义布局里,一个是用在 Fragment 里。
SupportMapFragment(推荐)
这是最省事的方式。直接在布局文件里声明:
<fragment
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
然后在 Activity 或 Fragment 里获取回调:
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(GoogleMap googleMap) {
// 地图加载完成,可以操作了
}
});
为什么推荐这个?因为它帮你处理了生命周期。地图的生命周期和 Fragment 是绑定的,你不需要手动去调用 onCreate()、onResume()、onDestroy() 这些方法。省心。
MapView(灵活但麻烦)
如果你想把地图嵌入到一个复杂的自定义 View 里,或者需要和别的 View 做动画联动,那就得用 MapView。
<com.google.android.gms.maps.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="200dp" />
但注意,MapView 不会自动管理生命周期。你得手动调用:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
我曾经在一个项目中为了做地图的缩放动画,不得不使用 MapView。结果漏掉了 onSaveInstanceState 的调用,导致屏幕旋转后地图状态丢失。嗯,这种细节最容易被忽略。
在地图上显示位置
地图加载好了,接下来就是把位置标上去。核心就是 GoogleMap 对象和 Marker。
添加标记(Marker)
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
LatLng position = new LatLng(39.9042, 116.4074); // 北京天安门
mMap.addMarker(new MarkerOptions()
.position(position)
.title("天安门")
.snippet("北京市中心"));
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(position, 12f));
}
这里有个小细节:moveCamera 是直接跳转,没有动画。如果你想要平滑移动,用 animateCamera:
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(position, 12f), 2000, null);
第二个参数是动画时长,单位毫秒。我个人习惯用 1000-2000 毫秒,太快了用户看不清,太慢了又显得拖沓。
显示当前位置
要显示用户自己的位置,需要先获取定位权限,然后启用 MyLocation 图层:
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
mMap.setMyLocationEnabled(true);
// 还可以显示定位按钮
mMap.getUiSettings().setMyLocationButtonEnabled(true);
}
启用后,地图右上角会出现一个定位按钮,点击后地图会移动到用户当前位置。同时,地图上会显示一个蓝色的圆点,代表用户位置。
MyLocationChangeListener,然后自己添加一个 Marker。但要注意,这个回调在 Android 12 以上已经废弃了,建议改用 FusedLocationProviderClient 获取位置后自行绘制。
更新位置
实际项目中,位置是动态变化的。比如外卖骑手、跑步轨迹。这时候你需要不断更新 Marker 的位置:
Marker marker = mMap.addMarker(new MarkerOptions().position(initialPos));
// 当位置更新时
marker.setPosition(newPos);
// 或者带动画
marker.setPosition(newPos, true); // 第二个参数是是否带动画
但要注意,频繁更新 Marker 位置可能会造成性能问题。我建议使用 Handler 或 WorkManager 控制更新频率,比如每 2 秒更新一次,而不是每 100 毫秒。
知识体系总览
下面这张图,把这一章的核心逻辑串起来了。你可以看到,从配置到展示,再到交互,每一步都有对应的组件和方法。
避坑指南
最后,分享几个我踩过的坑:
- API Key 泄露:我曾经把 Key 直接写在代码里,提交到了 GitHub 公开仓库。第二天就收到 Google 的警告邮件,说 Key 被滥用。赶紧去 Cloud Console 删掉重新生成,并加了限制。
- 地图加载不出来:检查一下你的 SHA-1 指纹。如果你用了多个签名(debug + release),每个都要在 Cloud Console 里添加。
- 定位权限:Android 11 以上,
ACCESS_FINE_LOCATION和ACCESS_COARSE_LOCATION都要在运行时申请。而且用户可以选择「仅在使用中允许」,这个要处理好。 - 模拟器问题:Google Maps 在模拟器上可能加载不出来,尤其是没有 Google Play 服务的模拟器。建议用真机调试。
嗯,地图集成这块内容不少,但核心就是配置、展示、操作这三步。把每一步的细节抠清楚,后面用起来就顺手了。
核心要点回顾:
- API Key 必须限制使用范围,防止被盗刷
- 优先使用 SupportMapFragment,省去生命周期管理的麻烦
- Marker 是显示位置的核心,支持标题、片段和动画
- 启用 MyLocation 图层可以快速显示用户当前位置