地图集成: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 里,结果被别人盗刷,一天跑了十几万次请求,账单直接爆炸。

⚠️ 重要提醒: 在 Cloud Console 中,务必为 API Key 添加 Android 应用限制。填入你的包名和 SHA-1 证书指纹。这样只有你的 App 才能用这个 Key。

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 提供了两种方式来展示地图:MapViewSupportMapFragment。说白了,一个是用在自定义布局里,一个是用在 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 位置可能会造成性能问题。我建议使用 HandlerWorkManager 控制更新频率,比如每 2 秒更新一次,而不是每 100 毫秒。

知识体系总览

下面这张图,把这一章的核心逻辑串起来了。你可以看到,从配置到展示,再到交互,每一步都有对应的组件和方法。

Google Maps 集成知识体系 1. 配置 Cloud Console + API Key 2. 展示方式 MapView / SupportMapFragment 3. 地图操作 GoogleMap 对象 配置要点 • 启用 Maps SDK for Android • 生成并限制 API Key • 添加依赖 + Manifest 配置 展示方式对比 • SupportMapFragment:推荐 • MapView:灵活但需手动管理 • 生命周期绑定是关键 核心操作 • 添加 Marker • 移动/缩放相机 • 显示当前位置 最终目标:在地图上显示位置 Marker + 定位 + 动态更新

避坑指南

最后,分享几个我踩过的坑:

  • API Key 泄露:我曾经把 Key 直接写在代码里,提交到了 GitHub 公开仓库。第二天就收到 Google 的警告邮件,说 Key 被滥用。赶紧去 Cloud Console 删掉重新生成,并加了限制。
  • 地图加载不出来:检查一下你的 SHA-1 指纹。如果你用了多个签名(debug + release),每个都要在 Cloud Console 里添加。
  • 定位权限:Android 11 以上,ACCESS_FINE_LOCATIONACCESS_COARSE_LOCATION 都要在运行时申请。而且用户可以选择「仅在使用中允许」,这个要处理好。
  • 模拟器问题:Google Maps 在模拟器上可能加载不出来,尤其是没有 Google Play 服务的模拟器。建议用真机调试。

嗯,地图集成这块内容不少,但核心就是配置、展示、操作这三步。把每一步的细节抠清楚,后面用起来就顺手了。

核心要点回顾:

  • API Key 必须限制使用范围,防止被盗刷
  • 优先使用 SupportMapFragment,省去生命周期管理的麻烦
  • Marker 是显示位置的核心,支持标题、片段和动画
  • 启用 MyLocation 图层可以快速显示用户当前位置
公众号:蓝海资料掘金营,微信deep3321