1. 欢迎
此 Codelab 是 Google Developers 培训团队开发的高级 Android 开发培训课程的一部分。如果您按顺序学习这些 Codelab,就能从本课程中获得最大价值。
如需详细了解本课程,请参阅高级 Android 开发概览。
简介
通过使用 Google 地图构建应用,您可以向应用添加卫星图像、强大的界面控件、位置跟踪和位置标记等功能。您可以通过显示自己的数据集中的信息(例如知名钓鱼区或攀岩区的地点),为标准 Google 地图增加价值。你还可以打造与现实世界关联的游戏,例如《Pokemon Go》。
在本次实践课中,您将创建一个名为 Wander 的 Google 地图应用。
您应当已掌握的内容
您应熟悉以下内容:
- Google 地图的基本功能。
 - 运行时权限。
 - 在 Android Studio 中创建、构建和运行应用。
 - 在 
build.gradle文件中添加外部库。 
学习内容
- 在您的应用中集成 Google 地图。
 - 显示不同的地图类型。
 - 设置 Google 地图的样式。
 - 向地图添加标记。
 - 允许用户在地图注点 (POI) 上放置标记。
 - 启用位置跟踪。
 - 启用 Google 街景。
 
您将执行的操作
- 从 Google API 控制台获取 API 密钥,并向您的应用注册该密钥。
 - 创建包含嵌入式 Google 地图的 
Wander应用。 - 为您的应用添加自定义功能,例如标记、样式设置和位置跟踪。
 - 在您的应用中启用位置跟踪和街景。
 
2. 应用概览
在本次实践课中,您将创建 Wander 应用,这是一个自定样式的 Google 地图。借助 Wander 应用,您可以将标记拖放到所需位置,实时查看自己的位置,以及查看街景全景图片。
  | 
  | 
3. 任务 1. 设置项目并获取 API 密钥
与 Places API 一样,Google Maps API 也需要 API 密钥。要获取 API 密钥,请在 Google API 控制台中注册您的项目。该 API 密钥与将此应用关联到其作者的数字证书相关联。如需详细了解如何使用数字证书以及为应用签名,请参阅为应用签名。
在本次实践课中,您将使用 API 密钥作为调试证书。如为调试版本签名中所述,调试证书在设计上是不安全的。使用 Google Maps API 的已发布 Android 应用需要第二个 API 密钥:发布证书的密钥。如需详细了解如何获取发布证书,请参阅获取 API 密钥。
Android Studio 包含一个 Google Maps Activity 模板,此模板可生成有用的模板代码。模板代码包括一个 google_maps_api.xml 文件,其中包含用于简化 API 密钥获取的链接。
1.1 使用地图模板创建 Wander 项目
- 新建一个 Android Studio 项目。
 - 将新应用命名为“Wander”。在进入 Add an Activity 页面之前,接受默认设置。
 - 选择 Google Maps Activity 模板。
 - 保留默认的 Activity Name 和 Layout Name。
 - 将标题更改为“Wander”然后点击 Finish。
 
Android Studio 会创建几个与地图相关的其他文件:
google_maps_api**.xml**
您可以使用此配置文件来保存 API 密钥。该模板会生成两个 google_maps_api.xml 文件:一个用于调试,另一个用于发布。调试证书的 API 密钥文件位于 src/debug/res/values。发布证书的 API 密钥文件位于 src/release/res/values。在本次实践课中,我们仅使用调试证书。
activity_maps.xml
此布局文件包含一个填充整个屏幕的 fragment。SupportMapFragment 类是 Fragment 类的子类。您可以在任何 ViewGroup 中使用 <fragment> 标记以及其他属性在布局文件中添加 SupportMapFragment:
android:name="com.google.android.gms.maps.SupportMapFragment"
MapsActivity.java
MapsActivity.java 文件会实例化 SupportMapFragment 类,并使用该类的 getMapAsync() 方法准备 Google 地图。包含 SupportMapFragment 的 activity 必须实现 OnMapReadyCallback 接口以及该接口的 onMapReady() 方法。getMapAsync() 方法会返回一个 GoogleMap 对象,表示地图已加载。
1.2 获取 API 密钥
- 打开调试版本的 
google_maps_api.xml文件。 
文件包含一条网址较长的评论。此网址的参数包含应用的特定信息。
- 将网址复制并粘贴到浏览器中。
 - 按照提示在 Google API 控制台中创建一个项目。由于提供网址中的参数,API 控制台就知道要自动启用 Google Maps Android API
 - 创建一个 API 密钥,然后点击 Restrict Key 以将该密钥的使用范围限制为 Android 应用。生成的 API 密钥应以 
AIza开头。 - 在 
google_maps_api.xml文件中,将密钥粘贴到显示YOUR_KEY_HERE的google_maps_key字符串中。 - 运行应用。您的 activity 中有一个嵌入式地图,并在澳大利亚悉尼设置了标记。(悉尼标记是模板的一部分,您稍后需要对其进行更改。)
 
4. 任务 2. 添加地图类型和标记
Google 地图包含以下几种地图类型:标准、混合、卫星、地形和“无”。在此任务中,您将添加一个包含选项菜单的应用栏,以便用户更改地图类型。您可以将地图的起始位置移到您的家庭住址。然后添加对标记的支持,标记用于指示地图上的单个位置,并且可以包含标签。
2.1 添加地图类型
用户想要的地图类型取决于他们需要的信息类型。在车内使用地图导航时,最好能清楚地看到街道名称。远足时,您可能更关心需要攀爬多少山才能到达山顶。在此步骤中,您会添加一个包含选项菜单的应用栏,用户可在此菜单中更改地图类型。
- 如需创建新的菜单 XML 文件,请右键点击 
res目录,然后依次选择 New >Android 资源文件。 - 在对话框中,将该文件命名为 
map_options。选择菜单作为资源类型。点击确定。 - 将新文件中的代码替换为以下代码,以创建地图选项。“无”因为“none”,所以省略了地图类型会导致完全不显示地图。
 
<?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>
- 为 
title属性创建字符串资源。 - 在 
MapsActivity文件中,更改类以扩展AppCompatActivity类,而不是扩展FragmentActivity类。使用AppCompatActivity将显示应用栏,因此会显示菜单。 - 在 
MapsActivity中,替换onCreateOptionsMenu()方法并膨胀map_options文件: 
@Override
public boolean onCreateOptionsMenu(Menu menu) {
   MenuInflater inflater = getMenuInflater();
   inflater.inflate(R.menu.map_options, menu);
   return true;
}
- 要更改地图类型,请对 
GoogleMap对象使用setMapType() 方法,并传入其中一个地图类型常量。 
替换 onOptionsItemSelected() 方法。粘贴以下代码,以便在用户选择其中一个菜单选项时更改地图类型:
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
       // Change the map type based on the user's selection.
       switch (item.getItemId()) {
           case R.id.normal_map:
               mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
               return true;
           case R.id.hybrid_map:
               mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
               return true;
           case R.id.satellite_map:
               mMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
               return true;
           case R.id.terrain_map:
               mMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN);
               return true;
           default:
               return super.onOptionsItemSelected(item);
       }
    }
- 运行应用。您可以使用应用栏中的菜单更改地图类型。请注意地图外观的变化。
 
2.2 移动默认地图位置
默认情况下,onMapReady() 回调包含的代码会将标记放置在创建 Google 地图时所处的澳大利亚悉尼。默认回调还会以动画形式将地图平移到悉尼。在此步骤中,您要在不放置标记的情况下让地图平移到您的住址,然后再缩放到您指定的级别。
- 在 
onMapReady()方法中,移除用于在悉尼放置标记并移动镜头的代码。 - 在浏览器中前往 www.google.com/maps,找到您的家。
 - 右键点击该地点,然后选择这儿是什么?
 
屏幕底部附近会弹出一个小窗口,其中包含纬度和经度等位置信息。
- 创建一个名为 
home的新LatLng对象。在LatLng对象中,使用您在浏览器中从 Google 地图中找到的坐标。 - 创建一个名为 
zoom的float变量,并将该变量设置为所需的初始缩放级别。通过以下列表,您可以了解在每个缩放级别看到的地图细节水平: 
1:全球5:大陆/洲10:城市15:街道20:建筑物
- 使用 
CameraUpdateFactory.newLatLngZoom()创建一个CameraUpdate对象,并传入LatLng对象和zoom变量。对GoogleMap对象调用moveCamera(),并传入新的CameraUpdate对象,以平移和缩放镜头: 
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(home, zoom));
- 运行应用。地图应平移到您家的位置,并放大到所需的级别。
 
2.3 添加地图标记
Google 地图可以使用标记(您使用 Marker 类创建标记)来挑选一个地点。默认标记使用标准的 Google 地图图标:
您可以扩展标记,以在信息窗口中显示上下文信息。
在此步骤中,您将在用户轻触并按住地图上的某个位置时添加一个标记。然后,您可以添加 InfoWindow,用于在用户点按标记时显示该标记的坐标。

- 在 
MapsActivity中创建一个名为setMapLongClick()的方法桩,它接受finalGoogleMap作为参数并返回void: 
private void setMapLongClick(final GoogleMap map) {}
- 使用 
GoogleMap对象的setOnMapLongClickListener()方法可将标记放置在用户轻触并按住的位置。传入一个新的OnMapLongClickListener实例来替换onMapLongClick()方法。传入参数是一个LatLng对象,其中包含用户按下位置的坐标: 
private void setMapLongClick(final GoogleMap map) {
   map.setOnMapLongClickListener(new GoogleMap.OnMapLongClickListener() {
       @Override
       public void onMapLongClick(LatLng latLng) {
       }
   });
}
- 在 
onMapLongClick()中,调用addMarker()方法。传入一个新的MarkerOptions对象,并将位置设置为传入的LatLng: 
map.addMarker(new MarkerOptions().position(latLng));
- 在 
onMapReady()方法的末尾调用setMapLongClick()。传入mMap。 - 运行应用。轻触并按住地图上的某个位置可放置标记。
 - 点按标记,使其在屏幕上居中。
 
导航按钮显示在屏幕左下方,可让用户使用 Google 地图应用导航到标记的位置。
要为标记添加信息窗口,请执行以下操作:
- 在 
MarkerOptions对象中,设置title字段和snippet字段。 - 在 
onMapLongClick()中,将title字段设置为“Dropped Pin”。将snippet字段设置为addMarker()方法中的位置坐标。 
map.setOnMapLongClickListener(new GoogleMap.OnMapLongClickListener() {
   @Override
   public void onMapLongClick(LatLng latLng) {
       String snippet = String.format(Locale.getDefault(),
               "Lat: %1$.5f, Long: %2$.5f",
               latLng.latitude,
               latLng.longitude);
       map.addMarker(new MarkerOptions()
               .position(latLng)
               .title(getString(R.string.dropped_pin))
               .snippet(snippet));
   }
});
- 运行应用。在地图上轻触并按住某个位置标记,点按此标记可显示信息窗口。
 
2.4 添加地图注点监听器
默认情况下,地图注点 (POI) 将与对应的图标一起显示在地图上。POI 包括公园、学校和政府大楼,等等。当地图类型设为 normal 时,商家 POI 也会显示在地图上。商家地图注点表示商店、餐馆和酒店等商家。
在此步骤中,您将向地图添加 GoogleMap.OnPoiClickListener。该点击监听器会立即在地图上放置标记,而不是等待触摸和通话。点击监听器还会显示包含地图注点名称的信息窗口。

- 在 
MapsActivity中创建一个名为setPoiClick()的方法桩,它接受finalGoogleMap作为参数,并返回void: 
private void setPoiClick(final GoogleMap map) {}
- 在 
setPoiClick()方法中,对传入的GoogleMap设置OnPoiClickListener: 
map.setOnPoiClickListener(new GoogleMap.OnPoiClickListener() {
   @Override
   public void onPoiClick(PointOfInterest poi) {
   }
});
- 在 
onPoiClick()方法中,在地图注点位置放置标记。将标题设置为地图注点的名称。将结果保存到名为poiMarker的变量中。 
public void onPoiClick(PointOfInterest poi) {
   Marker poiMarker = mMap.addMarker(new MarkerOptions()
       .position(poi.latLng)
       .title(poi.name);
}
- 对 
poiMarker调用showInfoWindow()可立即显示信息窗口。 
poiMarker.showInfoWindow();
- 在 
onMapReady()末尾调用setPoiClick()。传入mMap。 - 运行您的应用并查找一个地图注点(如公园)。点按相应地图注点以在其上放置标记,并在信息窗口中显示地图注点的名称。
 
5. 任务 3. 设置地图样式
您可以通过多种方式自定义 Google 地图,为地图赋予独特的外观和风格。
您可以使用可用的 XML 属性自定义 MapFragment 对象,就像自定义任何其他 fragment 一样。不过,在此步骤中,您可以使用 GoogleMap 对象中的方法自定义 MapFragment 的内容的外观和风格。您可以使用在线样式向导向地图添加样式并自定义标记。此外,您还需要为您的住址添加 GroundOverlay,以便随地图进行缩放和旋转。
3.1 向地图添加样式
要为您的地图创建自定义样式,您需要生成一个 JSON 文件来指定地图中地图项的显示方式。您不必手动创建此 JSON 文件:Google 提供了样式向导,它会在您可视化地图样式后为您生成 JSON。在本次实践课中,您将设置地图样式设置为“夜间模式”,表示地图在夜间使用的颜色昏暗、对比度较低。
- 在浏览器中前往 https://mapstyle.withgoogle.com/。
 - 选择 Create a Style。
 - 选择夜间主题。
 - 点击菜单底部的更多选项。
 - 在地图项类型列表底部,选择水域 >填充。将水域的颜色更改为深蓝色(例如 #160064)。
 - 点击完成。从出现的弹出式窗口中复制 JSON 代码。
 - 在 Android Studio 中,在 
res目录中创建一个名为raw的资源目录。在res/raw中创建一个名为map_style.json的文件。 - 将 JSON 代码粘贴到新的资源文件中。
 - 要为地图设置 JSON 样式,请对 
GoogleMap对象调用setMapStyle()。传入一个MapStyleOptions对象,用于加载 JSON 文件。setMapStyle()方法会返回一个布尔值,指示样式设置成功。如果无法加载,该方法会抛出Resources.NotFoundException。 
将以下代码复制到 onMapReady() 方法中,以设置地图样式。您可能需要为日志语句创建 TAG 字符串:
     try {
        // Customize the styling of the base map using a JSON object defined
        // in a raw resource file.
        boolean success = googleMap.setMapStyle(
           MapStyleOptions.loadRawResourceStyle(
                   this, R.raw.map_style));
        if (!success) {
            Log.e(TAG, "Style parsing failed.");
        }
     } catch (Resources.NotFoundException e) {
        Log.e(TAG, "Can't find style. Error: ", e);
     }
- 运行应用。当地图处于 
normal模式时,新样式应可见。 

3.2 设置标记的样式
通过设置地图标记的样式,您可以进一步对地图进行个性化设置。在此步骤中,您将更改默认的红色标记,以匹配夜间模式的配色方案。
- 在 
onMapLongClick()方法中,将以下代码行添加到MarkerOptions()构造函数中,以使用默认标记,但将颜色更改为蓝色: 
.icon(BitmapDescriptorFactory.defaultMarker
       (BitmapDescriptorFactory.HUE_BLUE))
- 运行应用。您放置的标记现在呈蓝色阴影,这更符合应用的夜间模式主题。
 
请注意,地图注点标记仍为红色,因为您没有向 onPoiClick() 方法添加样式。
3.3 添加叠加层
自定义 Google 地图的一种方式是在地图上绘制。如果您想突出特定类型的地点(例如热门钓鱼地点),此方法就会有用。支持以下三种叠加层类型:
- 形状:您可以向地图添加多段线、多边形和圆形。
 TileOverlay对象:图块叠加层用于定义在基本地图图块之上添加的一组图片。当您要向地图添加大量图像时,图块叠加层非常有用。典型的图块叠加层覆盖一大片地理区域。GroundOverlay对象:地面叠加层是固定在地图上的图像。与标记不同,底面叠层朝向地球表面,而不是屏幕。旋转、倾斜或缩放地图会改变图片的朝向。如果您想将单个图像固定在地图上的某一区域,便可使用地面叠加层
在此步骤中,您将向住址添加 Android 形状的地面叠加层。
- 下载此 Android 图片并将其保存在 
res/drawable文件夹中。 - 在 
onMapReady()中,在将镜头移至初始位置的调用之后,创建一个GroundOverlayOptions对象。将该对象分配给名为homeOverlay的变量: 
GroundOverlayOptions homeOverlay = new GroundOverlayOptions();
- 使用 
BitmapDescriptorFactory.fromResource()方法,基于上图创建一个BitmapDescriptor对象。将该对象传入GroundOverlayOptions对象的image()方法中: 
GroundOverlayOptions homeOverlay = new GroundOverlayOptions()
    .image(BitmapDescriptorFactory.fromResource(R.drawable.android));
- 通过调用 
position()方法为GroundOverlayOptions对象设置position属性。针对所需叠加层的宽度(以米为单位)传入homeLatLng对象和float。在下面的示例中,宽度为 100 米即可。 
GroundOverlayOptions homeOverlay = new GroundOverlayOptions()
     .image(BitmapDescriptorFactory.fromResource(R.drawable.android))
       .position(home, 100);
- 对 
GoogleMap对象调用addGroundOverlay()。传入您的GroundOverlayOptions对象: 
mMap.addGroundOverlay(homeOverlay);
- 运行应用。放大您的住址,您会看到以叠加层形式显示的 Android 图片。
 
6. 任务 4. 启用位置跟踪和街景
用户经常使用 Google 地图查看他们当前所在的位置,您也可以使用 Location Services API 获取设备位置信息。如需在地图上显示设备位置信息而不进一步使用 Location 数据,您可以使用位置数据层。
位置数据图层会在地图的右上角添加一个我的位置按钮。当用户点按此按钮时,地图将以设备所在位置为中心。如果设备处于静止状态,该位置会显示为蓝点;处于移动状态时,该位置会显示为蓝色 V 形。

您可以使用 Google 街景(给定地点的可导航全景照片)提供有关某个地点的更多信息。
在此任务中,您将启用位置数据图层和街景,以便当用户点按地图注点标记的信息窗口时,地图会进入街景模式。
4.1 启用位置跟踪
如需在 Google 地图中启用位置信息跟踪功能,只需一行代码即可。但是,您必须确保用户已授予位置权限(使用运行时-权限模式)。
在此步骤中,您会请求位置信息权限并启用位置信息跟踪。
- 在 
AndroidManifest.xml文件中,验证FINE_LOCATION权限是否已存在。在您选择 Google 地图模板时,Android Studio 插入了此权限。 - 如需在应用中启用位置信息跟踪功能,请在 
MapsActivity中创建一个名为enableMyLocation()的方法,该方法不带参数也不返回任何内容。 - 定义 
enableMyLocation()方法。检查ACCESS_FINE_LOCATION权限。如果已授予该权限,请启用位置图层。否则,请申请相应权限: 
private void enableMyLocation() {
   if (ContextCompat.checkSelfPermission(this,
           Manifest.permission.ACCESS_FINE_LOCATION)
           == PackageManager.PERMISSION_GRANTED) {
       mMap.setMyLocationEnabled(true);
   } else {
       ActivityCompat.requestPermissions(this, new String[]
                       {Manifest.permission.ACCESS_FINE_LOCATION},
               REQUEST_LOCATION_PERMISSION);
   }
}
- 从 
onMapReady()回调中调用enableMyLocation(),以启用位置图层。 - 替换 
onRequestPermissionsResult()方法。如果已授予权限,请调用enableMyLocation(): 
@Override
public void onRequestPermissionsResult(int requestCode,
       @NonNull String[] permissions,
       @NonNull int[] grantResults) {
   // Check if location permissions are granted and if so enable the
   // location data layer.
   switch (requestCode) {
       case REQUEST_LOCATION_PERMISSION:
           if (grantResults.length > 0
                   && grantResults[0]
                   == PackageManager.PERMISSION_GRANTED) {
               enableMyLocation();
               break;
           }
   }
}
- 运行应用。右上角现在会显示我的位置按钮,该按钮用于显示设备的当前位置。
 
4.2 启用街景
Google 地图提供的街景功能是某个地点的全景视图,带有用于沿指定路径导航的控件。街景没有覆盖全球。
在此步骤中,您将启用街景全景图片,当用户点按某个地图注点的信息窗口时,系统会将其激活。您需要做两件事:
- 区分地图注点标记与其他标记,因为您希望应用的功能仅适用于地图注点标记。这样,您可以在用户点按地图注点信息窗口时启动街景,但无法在用户点按任何其他类型的标记时启动。
 
Marker 类包含一个 setTag() 方法,您可以使用该方法附加数据。(数据可以是从 Object 扩展的任何内容)。您需要在用户点击地图注点时创建的标记上设置标记。
- 当用户点按 
OnInfoWindowClickListener中带标记的信息窗口时,请将MapFragment替换为StreetViewPanoramaFragment。(以下代码使用SupportMapFragment和SupportStreetViewPanoramaFragment来支持低于 API 12 的 Android 版本。) 
如果任何 fragment 在运行时发生变化,您必须将其添加到包含的 Activity 类中,而不是以静态方式在 XML 中添加。
标记地图注点标记
- 在 
onPoiClick()回调中,对poiMarker调用setTag()。传入任意字符串: 
poiMarker.setTag("poi");
将静态 SupportMapFragment 替换为运行时实例
- 打开 
activity_maps.xml,然后将该元素更改为一个框架布局,该布局将用作 fragment 的容器: 
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:id="@+id/fragment_container"
   android:layout_width="match_parent"
   android:layout_height="match_parent" />
- 在 
MapsActivity的onCreate()中,移除按 ID 查找SupportMapFragment的代码,因为 XML 中不再存在静态SupportMapFragment。请改为通过调用SupportMapFragment.newInstance()来创建SupportMapFragment的新运行时实例: 
SupportMapFragment mapFragment = SupportMapFragment.newInstance();
- 使用具有 
FragmentManager的 fragment 事务将 fragment 添加到FrameLayout: 
getSupportFragmentManager().beginTransaction()
       .add(R.id.fragment_container, mapFragment).commit();
- 保留触发地图异步加载的代码行:
 
mapFragment.getMapAsync(this);
设置 OnInfoWindowClickListener 并检查标记标记
- 在 
MapsActivity中创建一个名为setInfoWindowClickToPanorama()的方法桩,它接受GoogleMap作为参数并返回void: 
private void setInfoWindowClickToPanorama(GoogleMap map) {}
- 将 
OnInfoWindowClickListener设置为GoogleMap: 
map.setOnInfoWindowClickListener(
       new GoogleMap.OnInfoWindowClickListener() {
           @Override
           public void onInfoWindowClick(Marker marker) {
           }
       });
- 在 
onInfoWindowClick()方法中,检查标记是否包含您在onPoiClick()方法中设置的字符串标记: 
if (marker.getTag() == "poi") {}
将 SupportMapFragment 替换为 SupportStreetViewPanoramaFragment
- 如果标记包含该标记,请使用 
StreetViewPanoramaOptions对象指定街景全景图片的位置。将对象的position属性设置为传入标记的位置: 
StreetViewPanoramaOptions options =
       new StreetViewPanoramaOptions().position(
               marker.getPosition());
- 创建 
SupportStreetViewPanoramaFragment的新实例,并传入您创建的options对象: 
SupportStreetViewPanoramaFragment streetViewFragment
       = SupportStreetViewPanoramaFragment
       .newInstance(options);
- 启动 fragment 事务。将 fragment 容器的内容替换为新的 fragment 
streetViewFragment。将事务添加到返回堆栈,以便按“返回”按钮会返回到SupportMapFragment而不是退出应用: 
getSupportFragmentManager().beginTransaction()
       .replace(R.id.fragment_container,
               streetViewFragment)
       .addToBackStack(null).commit();
- 调用 
setPoiClick().后,在onMapReady()中调用setInfoWindowClickToPanorama(mMap) - 运行应用。放大显示街景覆盖的城市,例如山景城(Google 总部所在地),然后找到某个地图注点(例如公园)。点按地图注点即可放置标记,并显示信息窗口。点按信息窗口,进入街景模式,找到相应标记的位置。按返回按钮,返回到地图 fragment。
 

7. 解决方案代码
Wander 解决方案代码。
8. 编码挑战
挑战:如果您在没有街景图像的地点点按某个地图注点的信息窗口,会看到黑屏。
- 如需检查某个区域是否提供街景,请结合 
StreetViewPanorama.OnStreetViewPanoramaChangeListener实现OnStreetViewPanomaraReady回调。 - 如果所选区域不提供街景,请返回到地图 fragment 并显示错误。
 
9. 总结
- 要使用 Maps API,您需要通过 Google API 控制台获取 API 密钥。
 - 在 Android Studio 中,使用 Google Maps Activity 模板生成在应用布局中包含一个 
SupportMapFragment的Activity。该模板还会将ACCESS_FINE_PERMISSION添加到应用清单中,在您的 activity 中实现OnMapReadyCallback,并替换必需的onMapReady()方法。 
如需在运行时更改 GoogleMap 的地图类型,请使用 GoogleMap.setMapType() 方法。Google 地图可以是以下地图类型之一:
- 正常:典型的道路地图。显示道路、人类建造的一些特征以及河流等重要的自然特征。此外,还会显示道路和景观标签。
 - 混合:添加了道路地图的卫星照片数据。此外,还会显示道路和景观标签。
 - 卫星:照片数据。不显示道路和景观标签。
 - 地形:地形数据。地图包含颜色、轮廓线和标签以及透视阴影。此外,还会显示一些道路和标签。
 - 无**:无地图。
 
关于 Google 地图:
- 标记是特定地理位置的指示符。
 - 点按时,标记的默认行为是显示包含该位置相关信息的信息窗口。
 - 默认情况下,地图注点 (POI) 将与对应的图标一起显示在基本地图上。POI 包括公园、学校和政府大楼,等等。
 - 此外,如果地图类型为 
normal,商家 POI(商店、餐馆、酒店等)会默认显示在地图上。 - 您可以使用 
OnPoiClickListener捕获地图注点的点击次数。 - 您可以使用样式向导更改 Google 地图几乎所有元素的视觉外观。样式向导会生成 JSON 文件,您使用 
setMapStyle()方法将其传递到 Google 地图中。 - 您可以通过更改默认颜色,或用自定义图像替换标记图标来自定义标记。
 
其他重要信息:
- 使用地面叠加层将图像固定到某个地理位置。
 - 使用 
GroundOverlayOptions对象指定图片、图片的大小(以米为单位)以及图片的位置。将此对象传递给GoogleMap.addGroundOverlay()方法,将叠加层设置为地图。 - 如果您的应用具有 
ACCESS_FINE_LOCATION权限,您就可以使用mMap.setMyLocationEnabled(true)方法启用位置信息跟踪。 - Google 街景提供整个覆盖区域内以指定道路为中心的 360 度全景视图。
 - 使用 
StreetViewPanoramaFragment.newInstance()方法创建新的街景 fragment。 - 如需为视图指定选项,请使用 
StreetViewPanoramaOptions对象。将该对象传入newInstance()方法。 
10. 了解更多内容
相关概念文档位于 9.1:Google Maps API。
Android 开发者文档:
参考文档:
11. 家庭作业
此部分列出了在由讲师主导的课程中,学生学习此 Codelab 后可能需要完成的家庭作业。讲师自行决定是否执行以下操作:
- 根据需要布置作业。
 - 告知学生如何提交家庭作业。
 - 给家庭作业评分。
 
讲师可以酌情采纳这些建议,并且可以自由布置自己认为合适的任何其他家庭作业。
如果您是在自学此 Codelab,可随时通过这些家庭作业来检测您的知识掌握情况。
构建并运行应用
- 创建一个使用 Google Maps Activity 模板的新应用,该模板在应用启动时加载 Google 地图。
 - Google 地图加载完毕后,将镜头移到您的学校位置、家庭住址或其他对您而言有意义的位置。
 - 在地图上添加两个标记,一个位于您的学校位置,另一个位于您家或其他有意义的位置。
 - 通过更改默认颜色或用自定义图像替换默认标记图标来自定义标记图标。
 
提示:请参阅 onMapReady (GoogleMap googleMap) 文档。
回答以下问题
问题 1
当地图加载完毕并准备好在应用中使用时,系统会调用哪个方法?
onMapReady (GoogleMapgoogleMap)onMapLoaded (GoogleMapgoogleMap)onMapCreate (GoogleMapgoogleMap)onMapInitialize (GoogleMapgoogleMap)
问题 2
可以使用哪些 Android 组件将 Google 地图纳入您的应用中?
MapView和MapFragmentMapFragment和MapActivityMapView和MapActivity- 仅限 
MapFragment 
问题 3
Google Maps Android API 提供哪些类型的地图?
- 普通、混合、地形、卫星和路线图
 - 普通、混合、地形、卫星和“无”
 - 混合、地形、卫星、路线图和“无”
 - 普通、地形、卫星、图像地图和“none”
 
问题 4
为了向地图注点 (POI) 添加点击功能,您应实现哪个界面?
GoogleMap.OnPoiListenerGoogleMap.OnPoiClickListenerGoogleMap.OnPoiClickGoogleMap.OnPoiClicked
提交应用以进行评分
评分者的评分指南
检查应用是否具有以下功能:
- 当应用启动时,系统会正确显示 Google 地图,以表明已正确生成 API 密钥。
 - Google 地图加载完毕后,镜头会移至学生的家庭住址或学校位置。在代码中,此步骤应在 
onMapReady (GoogleMap googleMap)回调方法中执行。 - 标记会显示在学生的学校位置和其他位置(如学生的家)。
 - 这两个标记是自定义的。例如,标记使用非默认红色颜色或自定义图标。
 
12. 下一个 Codelab
如需查看“高级 Android 开发”培训课程中的所有 Codelab,请访问“高级 Android 开发 Codelab”着陆页。