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

使用集合让一切井井有条 根据您的偏好保存内容并对其进行分类。

此 Codelab 是“使用 Kotlin 进行高级 Android 开发”课程的一部分。如果您按顺序学习这些 Codelab,您将会充分发掘课程的价值,但并不强制要求这样做。“使用 Kotlin 进行高级 Android 开发”Codelab 着陆页列出了所有课程 Codelab。

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

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

前提条件

掌握了以下各方面的知识:

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

学习内容

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

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

Maps SDK for Android 需要 API 密钥。如需获取 API 密钥,请在 API 和服务网页中注册您的项目。API 密钥与数字证书相关联,此数字证书将应用与其作者关联。如需详细了解如何使用数字证书和为应用签名,请参阅为应用签名

在此 Codelab 中,您会使用调试证书的 API 密钥。调试证书在设计上不安全,如对您的调试 build 进行签名中所述。使用 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 模板。

  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.kt文件在 onCreate() 方法中实例化 SupportMapFragment,并使用此类的 getMapAsync() 来自动初始化地图系统和视图。包含 SupportMapFragment 的 activity 必须实现 OnMapReadyCallback 接口和该接口的 onMapReady() 方法。加载地图时,系统会调用 onMapReady() 方法。

第 2 步:获取 API 密钥

  1. 打开调试版本的 google_maps_api.xml 文件。
  2. 在此文件中,查找包含长网址的注释。此网址的参数包含应用的特定信息。
  3. 将此网址复制和粘贴到浏览器中。
  4. 根据提示在 APIs & Services网 页上创建项目。由于所提供网址中的参数,此网页知道要自动启用 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 中看到嵌入式地图,其中标记设置在澳大利亚悉尼。(悉尼标记是模板自带的,您稍后可以对其进行更改。)

第 3 步:重命名 mMap

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

  1. MapsActivity 中,右键点击 mMap,然后依次点击 Refactor> Rename...

  1. 将此变量名称更改为 map

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

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

标准地图

卫星地图

混合地图

地形地图

每种类型的地图都提供不同类型的信息。例如,在开车使用地图导航时,查看街道名称会有帮助,因此您可以使用标准选项。如果您要徒步旅行,地形地图将有助于确定登顶还需要再攀爬多远。

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

  1. 添加一个应用栏,其中包含一个允许用户更改地图类型的选项菜单。
  2. 将地图的起始位置移至您的住宅位置。
  3. 添加对标记的支持,标记指示地图上的单个位置,并可包含标签。

添加地图类型的菜单

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

  1. 如需创建新的菜单 XML 文件,请右键点击 res 目录,然后依次选择 New> Android Resource File
  2. 在对话框中,将文件命名为 map_options
  3. 选择 Menu 作为资源类型。
  4. 点击 OK
  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. 点击 可更改地图类型。请注意地图在不同模式下的外观变化。

默认情况下,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. 新建一个名为 homeLatLngLatLng 对象。在 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. 运行应用。地图应平移到您的住宅,缩放到所需级别,并在您的住宅上放置标记。

第 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. 点按标记,让标记在屏幕上居中。

第 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. 点按此标记可显示信息窗口。

第 4 步:添加地图注点监听器

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

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

  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. 点按地图注点,可在其上放置标记,并在信息窗口中显示地图注点名称。

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

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

如需为地图创建自定义样式,您可以生成 JSON 文件,用于指定地图中的地图项的显示方式。您无需手动创建此 JSON 文件。Google 提供 Maps Platform 样式设置向导,可在您直观地设置地图样式后,为您生成 JSON。在此任务中,您将使用复古主题为地图设置样式,也就是说,地图使用复古颜色,而您添加彩色的道路。

第 1 步:为地图创建样式

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

  1. 点击 More Options

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

  1. 点击 Finish

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

第 2 步:向您的地图添加样式

  1. 在 Android Studio 的 res 目录中,创建一个资源目录并将其命名为 raw。您可以使用 raw 目录资源,例如 JSON 代码。
  2. res/raw 中创建名为 map_style.json 的文件。
  3. 将您保存的 JSON 代码粘贴到这个新的资源文件中。
  4. MapsActivity 中,在 onCreate() 方法上方创建一个 TAG 类变量。这用于日志记录。
private val TAG = MapsActivity::class.java.simpleName
  1. 同样在 MapsActivity 中,创建一个接受 GoogleMapsetMapStyle() 函数。
  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 模式,系统应会显示采用复古主题和您所选道路颜色的新样式。

第 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() 方法添加样式,地图注点标记仍为红色。

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

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

步骤:添加底面叠层

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

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

  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 图片。

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

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

当用户点按此按钮时,地图将以设备所在位置为中心。设备处于静止状态时,位置以蓝点显示;设备处于移动状态时,位置以蓝色 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。如果是,请调用 enableMyLocation()
override fun onRequestPermissionsResult(
   requestCode: Int,
   permissions: Array<String>,
   grantResults: IntArray) {
   if (requestCode == REQUEST_LOCATION_PERMISSION) {
       if (grantResults.contains(PackageManager.PERMISSION_GRANTED)) {
           enableMyLocation()
       }
   }
}
  1. 运行应用。系统应会显示一个对话框,请求获取设备的位置信息。请继续并授予权限。

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

下载已完成的 Codelab 的代码。

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


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

下载 zip

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

Android 开发者文档:

参考文档:

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