使用 Kotlin 进行高级 Android 开发 04.1:Android Google 地图

1. 准备工作

使用 Google 地图构建应用,您可以向应用添加各种功能,例如卫星图像、强大的地图界面控件、位置信息跟踪和地点标记。您可以展示自己的数据集内的信息(例如有名钓鱼区或攀爬区的位置信息),从而为标准 Google 地图增加价值。您还可以打造游戏,让玩家在寻宝或增强现实等游戏中探索现实世界。

在本课程中,您会创建一个名为 Wander 的 Google 地图应用,此应用用于显示自定义地图并展示用户的位置信息。

前提条件

了解以下内容:

  • 如何使用 Android Studio 创建和运行基本的 Android 应用?
  • 如何创建和管理资源(例如字符串)?
  • 如何使用 Android Studio 重构代码和重命名变量?
  • 如何以用户身份使用 Google 地图?
  • 如何设置运行时权限?

学习内容

  • 如何从 Google API 控制台获取 API 密钥并向应用注册此密钥
  • 如何将 Google 地图集成到您的应用中
  • 如何显示不同的地图类型
  • 如何设置 Google 地图样式
  • 如何向地图添加标记
  • 如何允许用户在地图注点 (POI) 上放置标记
  • 如何启用位置信息跟踪功能
  • 如何创建包含嵌入式 Google 地图的 Wander 应用
  • 如何为应用创建自定义功能,例如标记和样式
  • 如何在应用中启用位置信息跟踪功能

2. 应用概览

在此 Codelab 中,您会创建 Wander 应用,此应用显示包含自定义样式的 Google 地图。利用 Wander 应用,您可以将标记拖放到相应位置上、添加叠层,以及实时查看自己的位置。

5b12eda7f467bc2f

3. 任务:设置项目并获取 API 密钥

Maps SDK for Android 需要 API 密钥。要获取 API 密钥,请在 API 和服务页面。该 API 密钥与将此应用关联到其作者的数字证书相关联。如需详细了解如何使用数字证书以及为应用签名,请参阅为应用签名

在此 Codelab 中,您将使用调试证书的 API 密钥。如为调试版本签名中所述,调试证书在设计上是不安全的。使用 Maps SDK for Android 的已发布 Android 应用需要第二个 API 密钥,即发布证书的密钥。如需详细了解如何获取发布证书,请参阅获取 API 密钥

Android Studio 包含一个 Google Maps Activity 模板,此模板可生成有用的模板代码。模板代码包括一个 google_maps_api.xml 文件,其中包含用于简化 API 密钥获取的链接。

第 1 步:使用地图模板创建 Wander 项目

  1. 新建一个 Android Studio 项目。
  2. 选择 Google Maps Activity 模板。

d6b874bb19ea68cd.png

  1. 将项目命名为 Wander
  2. 将最低 API 级别设置为 API 19。确保语言为 Kotlin
  3. 点击 Finish
  4. 应用构建完成后,请查看您的项目以及 Android Studio 为您创建的以下地图相关文件:

google_maps_api.xml - 使用此配置文件保存 API 密钥。该模板会生成两个 google_maps_api.xml 文件:一个用于调试,一个用于发布。调试证书的 API 密钥文件位于 src/debug/res/values。发布证书的 API 密钥文件位于 src/release/res/values。在此 Codelab 中,您只使用调试证书。

activity_maps.xml - 此布局文件包含一个填满整个屏幕的 fragment。SupportMapFragment 类是 Fragment 类的子类。SupportMapFragment 是在应用中放置地图的最简单方式。它是地图视图的封装容器,可自动处理必要的生命周期需求。

您可以使用任何 ViewGroup 中的 <fragment> 标记在布局文件中添加 SupportMapFragment,并包含一个额外的 name 属性。

android:name="com.google.android.gms.maps.SupportMapFragment"

MapsActivity.java - MapsActivity.java 文件会在 onCreate() 方法中实例化 SupportMapFragment,并使用类的getMapAsync(),用于自动初始化地图系统和视图。包含 SupportMapFragment 的 activity 必须实现 OnMapReadyCallback 接口以及该接口的 onMapReady() 方法。加载地图时,系统会调用 onMapReady() 方法。

第 2 步:获取 API 密钥

  1. 打开调试版 google_maps_api.xml 文件。
  2. 在此文件中,查找包含长网址的注释。此网址的参数包含应用的特定信息。
  3. 将网址复制并粘贴到浏览器中。
  4. 按照提示在 API 和服务页面。由于所提供网址中的参数,此网页知道要自动启用 Maps SDK for Android。
  5. 点击 Create an API Key
  6. 在下一页上,转到“API Keys”部分,然后点击您刚刚创建的密钥。
  7. 点击限制密钥,然后选择 Maps SDK for Android,以仅限 Android 应用使用该密钥。
  8. 复制生成的 API 密钥。它以“AIza"”开头。
  9. google_maps_api.xml 文件中,将密钥粘贴到显示 YOUR_KEY_HEREgoogle_maps_key 字符串中。
  10. 运行应用。您应可以在 activity 中看到嵌入式地图,其中标记设置在澳大利亚悉尼。(悉尼标记是模板自带的,您稍后可以对其进行更改。)

34dc9dd877c90996

第 3 步:重命名 mMap

MapsActivity 具有一个名为 mMap 的专用 lateinit var,其类型为 GoogleMap。为了遵循 Kotlin 命名惯例,请将 mMap 的名称更改为 map

  1. MapsActivity 中,右键点击 mMap,然后点击 Refactor >重命名...

e713ccb3384450c6.png

  1. 将变量名称更改为 map

请注意,onMapReady() 函数中对 mMap 的所有引用也会变为引用 map

4. 任务:添加地图类型

Google 地图包含多种地图类型:标准、混合、卫星、地形和“无”(完全没有地图)。

标准地图

卫星地图

混合地图

地形地图

每种类型的地图都会提供不同类型的信息。例如,在汽车中使用地图进行导航时,查看街道名称很有帮助,因此您可以使用常规选项。徒步旅行时,地形地图可以帮您确定还要攀爬多长距离才能到达山顶。

在此任务中,您将执行以下操作:

  1. 添加带有选项菜单的应用栏,以便用户更改地图类型。
  2. 将地图的起始位置移到您的家庭住址。
  3. 添加对标记的支持,标记指示地图上的单个位置,并可包含标签。

添加地图类型的菜单

在此步骤中,您会添加一个包含选项菜单的应用栏,用户可在此菜单中更改地图类型。

  1. 如需创建新的菜单 XML 文件,请右键点击 res 目录,然后选择 New >Android 资源文件
  2. 在对话框中,将文件命名为 map_options
  3. 选择菜单作为资源类型。
  4. 点击确定
  5. Code 标签页中,将新文件中的代码替换为以下代码,以创建地图菜单选项。“无”地图类型会被省略,因为“无”会使系统根本不包含任何地图。此步骤会导致错误,但您可以在下一步中解决此问题。
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto">
   <item
       android:id="@+id/normal_map"
       android:title="@string/normal_map"
       app:showAsAction="never" />
   <item
       android:id="@+id/hybrid_map"
       android:title="@string/hybrid_map"
       app:showAsAction="never" />
   <item
       android:id="@+id/satellite_map"
       android:title="@string/satellite_map"
       app:showAsAction="never" />
   <item
       android:id="@+id/terrain_map"
       android:title="@string/terrain_map"
       app:showAsAction="never" />
</menu>
  1. strings.xml 中,为 title 属性添加资源以解决错误。
<resources>
   ...
   <string name="normal_map">Normal Map</string>
   <string name="hybrid_map">Hybrid Map</string>
   <string name="satellite_map">Satellite Map</string>
   <string name="terrain_map">Terrain Map</string>
   <string name="lat_long_snippet">Lat: %1$.5f, Long: %2$.5f</string>
   <string name="dropped_pin">Dropped Pin</string>
   <string name="poi">poi</string>
</resources>
  1. MapsActivity 中,替换 onCreateOptionsMenu() 方法,并通过 map_options 资源文件膨胀菜单。
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
   val inflater = menuInflater
   inflater.inflate(R.menu.map_options, menu)
   return true
}
  1. MapsActivity.kt 中,替换 onOptionsItemSelected() 方法。使用地图类型常量来更改地图类型,以反映用户的选择。
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
   // Change the map type based on the user's selection.
   R.id.normal_map -> {
       map.mapType = GoogleMap.MAP_TYPE_NORMAL
       true
   }
   R.id.hybrid_map -> {
       map.mapType = GoogleMap.MAP_TYPE_HYBRID
       true
   }
   R.id.satellite_map -> {
       map.mapType = GoogleMap.MAP_TYPE_SATELLITE
       true
   }
   R.id.terrain_map -> {
       map.mapType = GoogleMap.MAP_TYPE_TERRAIN
       true
   }
   else -> super.onOptionsItemSelected(item)
}
  1. 运行应用。
  2. 点击 428da163b831115b 可更改地图类型。请注意地图外观在不同模式之间会如何变化。

6fa42970d87f5dc7

5. 任务:添加标记

默认情况下,onMapReady() 回调包含的代码会将标记放置在创建 Google 地图时所处的澳大利亚悉尼。默认回调还会以动画方式呈现地图,以便平移到悉尼。

在此任务中,您会将地图的相机移至您的住宅,缩放到您指定的级别,并在地图上放置标记。

第 1 步:缩放至您的住宅并添加标记

  1. MapsActivity.kt 文件中,找到 onMapReady() 方法。移除其中用于在悉尼放置标记并移动相机的代码。现在,您的方法应如下所示。
override fun onMapReady(googleMap: GoogleMap) {
   map = googleMap

}
  1. 按照这些说明查找您住宅的纬度和经度。
  2. 为纬度和经度分别创建一个值,然后输入两者的浮点值。
val latitude = 37.422160
val longitude = -122.084270
  1. 创建一个名为 homeLatLng 的新 LatLng 对象。在 homeLatLng 对象中,传入您刚刚创建的值。
val homeLatLng = LatLng(latitude, longitude)
  1. 针对您要在地图上放大到的程度创建 val。使用 15f 缩放级别。
val zoomLevel = 15f

缩放级别可控制您在地图上放大到多大程度。通过以下列表,您可以了解在每个缩放级别看到的地图细节水平:

  • 1:全球
  • 5:大陆/洲
  • 10:城市
  • 15:街道
  • 20:建筑物
  1. 通过对 map 对象调用 moveCamera() 函数,将相机移至 homeLatLng,并使用 CameraUpdateFactory.newLatLngZoom() 传入 CameraUpdate 对象。传入 homeLatLng 对象和 zoomLevel
map.moveCamera(CameraUpdateFactory.newLatLngZoom(homeLatLng, zoomLevel))
  1. 向地图上的 homeLatLng 添加标记。
map.addMarker(MarkerOptions().position(homeLatLng))

最终的方法应如下所示:

override fun onMapReady(googleMap: GoogleMap) {
   map = googleMap

   //These coordinates represent the latitude and longitude of the Googleplex.
   val latitude = 37.422160
   val longitude = -122.084270
   val zoomLevel = 15f

   val homeLatLng = LatLng(latitude, longitude)
   map.moveCamera(CameraUpdateFactory.newLatLngZoom(homeLatLng, zoomLevel))
   map.addMarker(MarkerOptions().position(homeLatLng))
}
  1. 运行应用。地图应该会平移到您的住宅,缩放到所需级别,并在您的住宅上放置标记。

fc939024778ee76.png

第 2 步:允许用户通过长按来添加标记

在此步骤中,您将在用户轻触并按住地图上的某个位置时添加标记。

  1. MapsActivity 中创建一个名为 setMapLongClick() 的方法桩,它接受 GoogleMap 作为参数。
  2. 向此地图对象附加 setOnMapLongClickListener 监听器。
private fun setMapLongClick(map:GoogleMap) {
   map.setOnMapLongClickListener { }
}
  1. setOnMapLongClickListener() 中,调用 addMarker() 方法。传入一个新的 MarkerOptions 对象,并将位置设置为传入的 LatLng
private fun setMapLongClick(map: GoogleMap) {
   map.setOnMapLongClickListener { latLng ->
       map.addMarker(
           MarkerOptions()
               .position(latLng)
       )
   }
}
  1. onMapReady() 方法结束时,使用 map 调用 setMapLongClick()
override fun onMapReady(googleMap: GoogleMap) {
   ...
  
   setMapLongClick(map)
}
  1. 运行应用。
  2. 轻触并按住地图,在某个位置放置标记。
  3. 点按标记,使其在屏幕上居中。

4ff8d1c1db3bca9e.png

第 3 步:为标记添加信息窗口

在此步骤中,您会添加 InfoWindow,用于在用户点按标记时显示标记坐标。

  1. setMapLongClick()setOnMapLongClickListener() 中,为 snippet 创建一个 val。代码段是显示在标题之后的附加文本。您的代码段会显示标记的纬度和经度。
private fun setMapLongClick(map: GoogleMap) {
   map.setOnMapLongClickListener { latLng ->
       // A snippet is additional text that's displayed after the title.
       val snippet = String.format(
           Locale.getDefault(),
           "Lat: %1$.5f, Long: %2$.5f",
           latLng.latitude,
           latLng.longitude
       )
       map.addMarker(
           MarkerOptions()
               .position(latLng)
       )
   }
}
  1. addMarker() 中,使用 R.string.dropped_pin 字符串资源将标记的 title 设置为“已放置图钉”。
  2. 将标记的 snippet 设置为 snippet

完成后的函数如下所示:

private fun setMapLongClick(map: GoogleMap) {
   map.setOnMapLongClickListener { latLng ->
       // A Snippet is Additional text that's displayed below the title.
       val snippet = String.format(
           Locale.getDefault(),
           "Lat: %1$.5f, Long: %2$.5f",
           latLng.latitude,
           latLng.longitude
       )
       map.addMarker(
           MarkerOptions()
               .position(latLng)
               .title(getString(R.string.dropped_pin))
               .snippet(snippet)
              
       )
   }
}
  1. 运行应用。
  2. 轻触并按住地图即可放置地点标记。
  3. 点按此标记可显示信息窗口。

63f210e6e47dfa29

第 4 步:添加 POI 监听器

默认情况下,地图注点 (POI) 将与对应的图标一起显示在地图上。POI 包括公园、学校和政府大楼,等等。当地图类型设为 normal 时,商家 POI 也会显示在地图上。商家 POI 表示商家,例如商店、餐馆和酒店。

在此步骤中,您将向地图添加 GoogleMap.OnPoiClickListener。此点击监听器会在用户点击 POI 时立即在地图上放置标记。此点击监听器还会显示包含 POI 名称的信息窗口。

  1. MapsActivity 中创建一个名为 setPoiClick() 的方法桩,它接受 GoogleMap 作为参数。
  2. setPoiClick() 方法中,对传入的 GoogleMap 设置 OnPoiClickListener
private fun setPoiClick(map: GoogleMap) {
   map.setOnPoiClickListener { poi ->

   }
}
  1. setOnPoiClickListener() 中,为标记创建 val poiMarker
  2. 使用 map.addMarker() 将它设置为标记,并使用 MarkerOptionstitle 设置为相应地图注点的名称。
private fun setPoiClick(map: GoogleMap) {
   map.setOnPoiClickListener { poi ->
       val poiMarker = map.addMarker(
           MarkerOptions()
               .position(poi.latLng)
               .title(poi.name)
       )
   }
}
  1. setOnPoiClickListener() 函数中,对 poiMarker 调用 showInfoWindow() 即可立即显示信息窗口。
poiMarker.showInfoWindow()

setPoiClick() 函数的最终代码应如下所示。

private fun setPoiClick(map: GoogleMap) {
   map.setOnPoiClickListener { poi ->
       val poiMarker = map.addMarker(
           MarkerOptions()
               .position(poi.latLng)
               .title(poi.name)
       )
       poiMarker.showInfoWindow()
   }
}
  1. onMapReady() 结束时,调用 setPoiClick() 并传入 map
override fun onMapReady(googleMap: GoogleMap) {
   ...

   setPoiClick(map)
}
  1. 运行您的应用并查找一个地图注点,例如公园或咖啡馆。
  2. 点按 POI,在其上放置标记,并在信息窗口中显示该 POI 的名称。

f4b0972c75d5fa5f.png

6. 任务:设置地图样式

您可以通过多种方式自定义 Google 地图,为地图赋予独特的外观和风格。

您可以使用可用的 XML 属性自定义 MapFragment 对象,就像自定义任何其他 fragment 一样。不过,在此步骤中,您可以使用 GoogleMap 对象中的方法自定义 MapFragment内容的外观和风格。

若要为您的地图创建自定义样式,您需要生成一个 JSON 文件,以指定地图中地图项的显示方式。您无需手动创建此 JSON 文件。Google 提供了 Maps Platform 样式设置向导,在您直观地设置地图样式后,该向导会为您生成 JSON。在此任务中,您将使用复古主题为地图设置样式,这意味着地图会使用复古颜色并添加彩色道路。

第 1 步:为地图创建样式

  1. 在浏览器中前往 https://mapstyle.withgoogle.com/
  2. 选择 Create a Style
  3. 选择 Retro

208b3d3aeab0d9b6

  1. 点击更多选项

4a35faaf9535ee82

  1. 选择道路 >填充
  2. 将道路的颜色更改为您选择的任意颜色(例如粉色)。

92c3293749293a4c

  1. 点击完成

f1bfe8585eb69480.png

  1. 从出现的对话框中复制 JSON 代码,如果需要,将其存储在纯文本备注中,供下一步使用。

3c32168b299d6420

第 2 步:将样式添加到地图

  1. 在 Android Studio 的 res 目录中,创建一个资源目录,并将其命名为 raw。您可以使用 JSON 代码等 raw 目录资源。
  2. res/raw 中创建名为 map_style.json 的文件。
  3. 将您保存的 JSON 代码粘贴到这个新的资源文件中。
  4. MapsActivity 中,在 onCreate() 方法上方创建一个 TAG 类变量。这用于日志记录目的。
private val TAG = MapsActivity::class.java.simpleName
  1. MapsActivity 中,创建一个 setMapStyle() 函数,该函数接受 GoogleMap
  2. setMapStyle() 中,添加 try{} 代码块。
  3. try{} 代码块中,为样式设置的成功状态创建 val success。(添加以下 catch 代码块。)
  4. try{} 代码块中,为地图设置 JSON 样式,然后对 GoogleMap 对象调用 setMapStyle()。传入一个 MapStyleOptions 对象,用于加载 JSON 文件。
  5. 将结果分配给 successsetMapStyle() 方法会返回一个布尔值,指示解析样式文件并设置样式的成功状态。
private fun setMapStyle(map: GoogleMap) {
   try {
       // Customize the styling of the base map using a JSON object defined
       // in a raw resource file.
       val success = map.setMapStyle(
           MapStyleOptions.loadRawResourceStyle(
               this,
               R.raw.map_style
           )
       )
   }
}
  1. 对结果为 false 的 success 添加 if 语句。如果样式设置失败,请输出一条日志,指明解析已失败。
private fun setMapStyle(map: GoogleMap) {
   try {
       ...
       if (!success) {
           Log.e(TAG, "Style parsing failed.")
       }
   }
}
  1. 添加一个 catch{} 代码块,以处理缺少样式文件的情况。在 catch 代码块中,如果无法加载文件,则会抛出 Resources.NotFoundException
private fun setMapStyle(map: GoogleMap) {
   try {
       ...
   } catch (e: Resources.NotFoundException) {
       Log.e(TAG, "Can't find style. Error: ", e)
   }
}

完成后的方法应类似于以下代码段:

private fun setMapStyle(map: GoogleMap) {
   try {
       // Customize the styling of the base map using a JSON object defined
       // in a raw resource file.
       val success = map.setMapStyle(
           MapStyleOptions.loadRawResourceStyle(
               this,
               R.raw.map_style
           )
       )

       if (!success) {
           Log.e(TAG, "Style parsing failed.")
       }
   } catch (e: Resources.NotFoundException) {
       Log.e(TAG, "Can't find style. Error: ", e)
   }
}
  1. 最后,在传入 GoogleMap 对象的 onMapReady() 方法中调用 setMapStyle() 方法。
override fun onMapReady(googleMap: GoogleMap) {
   ...
   setMapStyle(map)
}
  1. 运行应用。
  2. 将地图设置为 normal 模式,新样式应该会显示复古主题和所选颜色的道路。

b59d6cb81f02a14f.png

第 3 步:设置标记的样式

通过设置地图标记的样式,您可以进一步对地图进行个性化设置。在此步骤中,您将默认的红色标记更改为更有趣的内容。

  1. onMapLongClick() 方法中,将以下代码行添加到构造函数的 MarkerOptions() 中,以使用默认标记,但将颜色更改为蓝色。
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE))

现在,onMapLongClickListener() 如下所示:

map.setOnMapLongClickListener { latLng ->
   // A snippet is additional text that's displayed after the title.
   val snippet = String.format(
       Locale.getDefault(),
       "Lat: %1$.5f, Long: %2$.5f",
       latLng.latitude,
       latLng.longitude
   )
   map.addMarker(
       MarkerOptions()
           .position(latLng)
           .title(getString(R.string.dropped_pin))
           .snippet(snippet)
         .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE))
   )
}
  1. 运行应用。长按后显示的标记现在会显示蓝色阴影。请注意,由于您未向 onPoiClick() 方法添加样式,因此 POI 标记仍显示为红色。

b9916bca3c367e3.png

7. 任务:添加叠加层

您可以自定义 Google 地图,其中一个方法是在 Google 地图上进行绘制。如果您想突出显示特定类型的位置(如热门钓鱼点),则此方法非常有用。

  • 形状:您可以向地图添加多段线多边形圆形
  • GroundOverlay 对象:地面叠加层是固定在地图上的图像。与标记不同,底面叠层朝向地球表面,而不是屏幕。旋转、倾斜或缩放地图会改变图片的朝向。如果您想将单个图片固定在地图上的某一区域,便可使用底面叠层。

步骤:添加底面叠层

在此任务中,您会将 Android 形状的底面叠层添加到您的住宅位置。

  1. 下载 此 Android 图片,并将其保存在 res/drawable 文件夹中。(请确保文件名为 android.png。)

61fabd56a0841b44

  1. onMapReady() 中,在将摄像头移至住宅位置的调用之后,创建一个 GroundOverlayOptions 对象。
  2. 将该对象分配给名为 androidOverlay 的变量。
val androidOverlay = GroundOverlayOptions()
  1. 使用 BitmapDescriptorFactory.fromResource() 方法根据下载的图片资源创建 BitmapDescriptor 对象。
  2. 将生成的 BitmapDescriptor 对象传入 GroundOverlayOptions 对象的 image() 方法。
val androidOverlay = GroundOverlayOptions()
   .image(BitmapDescriptorFactory.fromResource(R.drawable.android))
  1. 为所需叠层的宽度(以米为单位)创建 float overlaySize。在本例中,100f 的宽度效果较好。

通过调用 position() 方法为 GroundOverlayOptions 对象设置 position 属性,并传入 homeLatLng 对象和 overlaySize

val overlaySize = 100f
val androidOverlay = GroundOverlayOptions()
   .image(BitmapDescriptorFactory.fromResource(R.drawable.android))
   .position(homeLatLng, overlaySize)
  1. GoogleMap 对象调用 addGroundOverlay() 并传入您的 GroundOverlayOptions 对象。
map.addGroundOverlay(androidOverlay)
  1. 运行应用。
  2. zoomLevel 的值更改为 18f,以查看叠层形式的 Android 图片。

b1b25b0acd6a9807.png

8. 任务:启用位置跟踪

用户经常使用 Google 地图查看自己的当前位置。要在地图上显示设备位置,您可以使用位置数据层

位置数据层会向地图添加“我的位置”图标。

f317f84dcb3ac3a1.png

当用户点按此按钮时,地图将以设备所在位置为中心。如果设备处于静止状态,该位置会显示为蓝点;处于移动状态时,该位置会显示为蓝色 V 形。

在此任务中,您会启用位置数据图层。

步骤:请求位置信息权限

如需在 Google 地图中启用位置信息跟踪功能,只需一行代码即可。但是,您必须确保用户已授予位置权限(使用运行时-权限模式)。

在此步骤中,您会请求位置信息权限并启用位置信息跟踪。

  1. AndroidManifest.xml 文件中,验证 FINE_LOCATION 权限是否已存在。在您选择 Google 地图模板时,Android Studio 插入了此权限。
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  1. MapsActivity 中,创建一个 REQUEST_LOCATION_PERMISSION 类变量。
private val REQUEST_LOCATION_PERMISSION = 1
  1. 如需检查是否授予权限,请在 MapsActivity 中创建一个名为 isPermissionGranted() 的方法。在此方法中,检查用户是否已授予权限。
private fun isPermissionGranted() : Boolean {
  return ContextCompat.checkSelfPermission(
       this,
      Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
}
  1. 如需在应用中启用位置跟踪功能,请在 MapsActivity 中创建一个名为 enableMyLocation() 的方法,该方法不带参数也不返回任何内容。在里面,检查 ACCESS_FINE_LOCATION 权限。如果已授予该权限,请启用位置图层。否则,请申请该权限。
private fun enableMyLocation() {
   if (isPermissionGranted()) {
       map.isMyLocationEnabled = true 
   }
   else {
       ActivityCompat.requestPermissions(
           this,
           arrayOf<String>(Manifest.permission.ACCESS_FINE_LOCATION),
           REQUEST_LOCATION_PERMISSION
       )
   }
}
  1. onMapReady() 回调中调用 enableMyLocation(),以启用位置图层。
override fun onMapReady(googleMap: GoogleMap) {
   ...
   enableMyLocation()
}
  1. 替换 onRequestPermissionsResult() 方法。检查 requestCode 是否等于 REQUEST_LOCATION_PERMISSION。如果已授予,则表示已授予权限。如果授予权限,还要检查 grantResults 数组的第一个槽位中是否包含 PackageManager.PERMISSION_GRANTED。如果为 true,请调用 enableMyLocation()
override fun onRequestPermissionsResult(
   requestCode: Int,
   permissions: Array<String>,
   grantResults: IntArray) {
   if (requestCode == REQUEST_LOCATION_PERMISSION) {
       if (grantResults.contains(PackageManager.PERMISSION_GRANTED)) {
           enableMyLocation()
       }
   }
}
  1. 运行应用。系统应会显示一个对话框,请求获取设备的位置信息。请继续并授予权限。

da7e23e00ec762c1.png

现在,地图会使用蓝点显示设备的当前位置。请注意,地图中有一个位置按钮。如果您移动地图以离开您所在的位置,然后点击此按钮,则系统会让地图重新以设备所在位置为中心。

5b12eda7f467bc2f

9. 解决方案代码

下载已完成的 Codelab 的代码。

$  git clone https://github.com/googlecodelabs/android-kotlin-geo-maps

或者,您也可以下载 ZIP 文件形式的仓库,将其解压缩并在 Android Studio 中打开。

10. 总结

恭喜!您向 Android Kotlin 应用添加了 Google 地图,并为其设置了样式。

11. 了解更多内容

Android 开发者文档:

参考文档:

12. 下一个 Codelab

如需查看指向本课程中其他 Codelab 的链接,请参阅“使用 Kotlin 进行高级 Android 开发”Codelab 着陆页