YOLP Android Map SDK -> Mapbox Android SDK移行ガイド

Android用Mapbox Maps SDK は、アンドロイド用のベクター・マップライブラリです。このガイドでは、Android Studioを用いたAndroid用Mapbox Maps SDKのインストール方法、マップの読み込み方法、マップ・スタイルの変更、複数のピンをマップ上に配置する方法について説明します。

メモ

YOLPをご利用の場合、Android用Mapbox Maps SDKは Yahoo! Android Map SDKと類似した機能を提供している事がおわかり頂けると思います。異なる点は、ガイド中で本メモの様な形式で 表記します。

Android Studioでプロジェクトを作成する

Android Studioにまず慣れてみましょう。最初に、空のアクティビティを含む新たなプロジェクトを作成してください。新しいAndroid Studioプロジェクトを以下のオプションから作成します:

  • 「Select the form factors your app will run on」で、「Phone and Tablet」をチェックします。
  • Minimum SDKの場合、API 14: Android 4.0.0 (IceCreamSandwich)を選択します。 (これは、Android用Mapbox Maps SDKに対応する最も低いAPIのレベルです。)
  • Nextをクリックして、アクティビティの選択スクリーンに進みます。
  • Empty Activityを選択して、Nextをクリックします。
  • デフォルトのアクティビティ名とレイアウト名を確認し、Finishをクリックします。

Android用Maps SDKのインストール

アプリの作成前に、インストール・ガイドに従って、Android用Mapbox Maps SDKをインストールしてください。本インストール・ガイドでは、既にAndroid Studioをダウンロードしており、また、新たなプロジェクトを作成済みである事を前提に説明します。Android用Mapbox Maps SDKをインストールするため、プロジェクト内の4個の異なるファイルに変更を加えます。対象の4ファイルは以下の通りです:

  • build.gradle (Module:App): Android Studioは、リソースとソースコードをAPKにコンパイルするのに、Gradleを使用します。このプレーンテキストファイルは、Android用Mapbox Maps SDKを記載し、ビルドの設定や依存性のリストに使用します。
  • AndroidManifest.xml: Mapboxに関する許可を記載し、アプリケーションのコンポーネント情報を入力する場所です。
  • MainActivity.java: Mapboxのクラスとメソッドを指定するJavaファイルです。
  • activity_main.xml: マップ・ビューのプロパティを設定する場所です。

マップ・ビューの設定

メモ

Yahoo! Android Map SDKをご存知の場合、Mapboxのマップ・ビューがYahoo! Android Map SDKのマップ・ビューに似ていることにお気づきかと思います。Browse the Android用Mapbox Maps SDKのAPIレファレンスを参照し、利用可能な全てのメソッドについてご確認ください。

カメラの位置や画面上のコンパスの位置など、アクティビティのレイアウトファイル上で、様々なマップの特徴を設定できます。インストール中にactivity_main.xmlファイルに記載したコードを、以下のコードに書き換え、マップの中心をウルグアイに設定し、ズーム・レベルを上げてください:

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
    <FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:mapbox="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
<com.mapbox.mapboxsdk.maps.MapView
    android:id="@+id/mapView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    mapbox:mapbox_cameraTargetLat="-32.557013"
    mapbox:mapbox_cameraTargetLng="-56.149056"
    mapbox:mapbox_cameraZoom="5.526846"/>
</FrameLayout>

マップ・スタイルの変更

メモ

Yahoo! Android Map SDKをご存知の場合、 Mapboxのセット・スタイルが Yahoo! Android Map SDKのセットマップ・タイプに似ていることがお気づきになると思います。

Android用Mapbox Maps SDKには様々なマップ・スタイルのバンドルが含まれています。Maps SDKのスタイルクラスから、普通のデザインに加え、現在ご提供させて頂いている様々なスタイルバンドルのリストにアクセスできます。この例では、Android用Mapbox Maps SDKには含まれていないMapboxデザインスタイルを使用します。

Mapbox MapクラスのsetStyle(); メソッドを使用し、マップ・スタイルをプログラミングする必要があります。このメソッドはURLを通して作成するスタイル・オブジェクトを必要とします。URLから作成後、様々な画像、ソース、レイヤーをスタイルに追加できます。

MainActivity.java
mapboxMap.setStyle(new Style.Builder().fromUri("mapbox://styles/your-mapbox-username/your-style-ID"), new Style.OnStyleLoaded() {
  @Override
  public void onStyleLoaded(@NonNull Style style) {

  }
});

もしくは

MainActivity.java
mapView.getMapAsync(new OnMapReadyCallback() {
  @Override
  public void onMapReady(MapboxMap mapboxMap) {
      MainActivity.this.mapboxMap = mapboxMap;
  }
});

上記のコードを入力後、Android Studioが注意を促す赤いメッセージを表示する場合があります。これは、MainActivity.javaで参照したクラスをインポートしていない場合に起こります。

Alt + Enter (Macコンピューターでは Option + Return)を押と、これらのクラスを自動的にインポート出来ます。また、代わりに、MainActivity.java上で、public class MainActivity extends AppCompatActivityと表記されている文字列の上部に、マニュアル操作で以下を追加することも出来ます。

アプリケーションを作成するには、「Run 'app'」ボタン (または、MacコンピューターのControl + R) をクリックします。

Android Studioのビルドは数秒かかりますが、エラーなく完了した場合、事前に設定をおこなったAndroidデバイスのエミュレータでテストを行う事が出来ます。どのようなアプローチで作成しても、同じ結果、つまり初期のマップ・スタイルがMapboxが認識するthe mapbox://styles/mapbox/cjf4m44iw0uza2spb3q0a7s41スタイルに変更された状態を確認出来ます。

マーカーの追加

メモ

Yahoo! Android Map SDKをご存知の場合、 Mapboxのシンボル・レイヤーがYahoo! Android Map SDKのピン・オーバーレイに類似していることがわかります。利用可能な全てのメソッドについては、Android用Mapbox Maps SDK のAPIレファレンスを参照してください。

次に、3つのマーカーをマップに追加します。マーカーをマップに追加するには、以下に説明する、3つのプロセスがあります:

  1. 世界のどの位置にマーカーを表示するのかを指定します。
  2. マップ上でマーカーをどう表示するのかを指定します。
  3. マーカーを、新たなレイヤーとして、マップ・スタイルに追加します。

MainActivity.javaファイルでこの3つのプロセスを行います。

GeoJSONのフィーチャ・コレクションを使用し、マーカーの位置を指定します。まずは、GeoJSONに関連する依存関係をインポートしてください。緯度と経度のフォーマットのユニークなコーディネートから成るフィーチャーのアレイを作成し、そして、そのアレイからGeoJSONのフィーチャ・コレクションを作成し、データ・ソースとしてマップ・スタイルに追加してください。

MainActivity.java
List<Feature> symbolLayerIconFeatureList = new ArrayList<>();
symbolLayerIconFeatureList.add(Feature.fromGeometry(
Point.fromLngLat(-57.225365, -33.213144)));
symbolLayerIconFeatureList.add(Feature.fromGeometry(
Point.fromLngLat(-54.14164, -33.981818)));
symbolLayerIconFeatureList.add(Feature.fromGeometry(
Point.fromLngLat(-56.990533, -30.583266)));
mapboxMap.setStyle(new Style.Builder().fromUri("mapbox://styles/mapbox/cjf4m44iw0uza2spb3q0a7s41")
// Add the SymbolLayer icon image to the map style
.withImage(ICON_ID, BitmapFactory.decodeResource(
MainActivity.this.getResources(), R.drawable.red_marker))
// Adding a GeoJson source for the SymbolLayer icons.
.withSource(new GeoJsonSource(SOURCE_ID,
FeatureCollection.fromFeatures(symbolLayerIconFeatureList)))

マーカーのスタイルを指定する

次に、マップ・スタイルにアイコン・イメージを追加し、次の段階でシンボル・レイヤーの追加時に、そのアイコンを利用可能にします。

MainActivity.java
// シンボル・レイヤーアイコン画像をマップ・スタイルに追加します。
.withImage(ICON_ID, BitmapFactory.decodeResource(
MainActivity.this.getResources(), R.drawable.red_marker))

マーカーをマップに追加する

MainActivity.java
// シンボル・レイヤーアイコン用に、GeoJson sourceソースを追加します。
// 実際のシンボル・レイヤーをマップ・スタイルに追加します。
// 赤いマーカー アイコンの下部が、座標ポイントに固定のアイコン中央ではなく、座標に固定するようにオフセットを追加します。
// これは常に必要なオフセットではなく、
// シンボル・レイヤーアイコンの画像に依存します。
.withLayer(new SymbolLayer(LAYER_ID, SOURCE_ID)
.withProperties(PropertyFactory.iconImage(ICON_ID),
iconAllowOverlap(true),
iconOffset(new Float[] {0f, -9f}))
), new Style.OnStyleLoaded() {

アプリケーションを再作動してください。赤いマーカーがウルグアイの上に表示されます。

完成したプロダクト

MainActivity.java
package com.mapbox.mapboxandroiddemo.examples.styles;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.FeatureCollection;
import com.mapbox.geojson.Point;
import com.mapbox.mapboxandroiddemo.R;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.style.layers.PropertyFactory;
import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import java.util.ArrayList;
import java.util.List;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAllowOverlap;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconOffset;
/**
* {@link SymbolLayer} アイコンをマップ上に表示します。
*/
public class MainActivity extends AppCompatActivity implements OnMapReadyCallback {
    private static final String SOURCE_ID = "SOURCE_ID";
    private static final String ICON_ID = "ICON_ID";
    private static final String LAYER_ID = "LAYER_ID";
    private MapView mapView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Mapboxのアクセス・トークンをここで設定します。これはアプリケーションのオブジェクト内または
        // マップ・ビューを含む同じアクティビティ内でコールされる必要があります。
        Mapbox.getInstance(this, getString(R.string.access_token));
        // ここには、XMLのマップ・ビューが含まれており、アクセス・トークンの設定後にコールされる必要があります。
        setContentView(R.layout.activity_main);
        mapView = findViewById(R.id.mapView);
        mapView.onCreate(savedInstanceState);
        mapView.getMapAsync(this);
    }
    @Override
    public void onMapReady(@NonNull final MapboxMap mapboxMap) {
        List<Feature> symbolLayerIconFeatureList = new ArrayList<>();
        symbolLayerIconFeatureList.add(Feature.fromGeometry(
            Point.fromLngLat(-57.225365, -33.213144)));
        symbolLayerIconFeatureList.add(Feature.fromGeometry(
            Point.fromLngLat(-54.14164, -33.981818)));
        symbolLayerIconFeatureList.add(Feature.fromGeometry(
            Point.fromLngLat(-56.990533, -30.583266)));
            mapboxMap.setStyle(new Style.Builder().fromUri("mapbox://styles/mapbox/cjf4m44iw0uza2spb3q0a7s41")
        // シンボル・レイヤーアイコン画像をマップ・スタイルに追加します。
        .withImage(ICON_ID, BitmapFactory.decodeResource(
            MainActivity.this.getResources(), R.drawable.red_marker))
        // シンボル・レイヤーアイコン用に、GeoJson sourceソースを追加します。
        .withSource(new GeoJsonSource(SOURCE_ID,
            FeatureCollection.fromFeatures(symbolLayerIconFeatureList)))
        // 実際のシンボル・レイヤーをマップ・スタイルに追加します。
        // 赤いマーカー アイコンの下部が、座標ポイントに固定のアイコン中央ではなく、座標に固定するようにオフセットを追加します。
        // これは常に必要なオフセットではなく、
        // シンボル・レイヤーアイコンの画像に依存します。
        .withLayer(new SymbolLayer(LAYER_ID, SOURCE_ID)
        .withProperties(PropertyFactory.iconImage(ICON_ID),
            iconAllowOverlap(true),
            iconOffset(new Float[] {0f, -9f}))
        ), new Style.OnStyleLoaded() {
    @Override
    public void onStyleLoaded(@NonNull Style style) {
        // マップが設定され、スタイルが読み込まれました。追加のデータを加えるか、マップ他の必要な調整を行う事ができます。
        }
    });
    }
    @Override
    public void onResume() {
        super.onResume();
        mapView.onResume();
    }
    @Override
    protected void onStart() {
        super.onStart();
        mapView.onStart();
    }
    @Override
    protected void onStop() {
        super.onStop();
        mapView.onStop();
    }
   @Override
    public void onPause() {
        super.onPause();
        mapView.onPause();
    }
    
    @Override
    public void onLowMemory() {
        super.onLowMemory();
        mapView.onLowMemory();
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mapView.onDestroy();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        mapView.onSaveInstanceState(outState);
    }
}