googleMap第5回 PlaceAPIとマーカーのセット | API and Marker | Android

スポンサーリンク

AndroidでGoogleMapアプリ開発

第1回 表示
第2回 表示形式 衛星、地図、地形図
第3回 マーカーと直線
第4回 googleMapのエラー
第5回 PlaceAPIとマーカーのセット
第6回 現在地 GPSの実装
第7回 トラッキング
第8回 様々な技法

第4回までにおいてgoogleMapにおける一通りの基本操作を説明しました。今回はgooglePlaceAPIのJSONを用いて、例えば近くのコンビニやATMを表示させるといったことを実装させる方法について説明します。

スポンサーリンク

Volleyを用いたJSON解析

Volley実装方法についてはこちらを参考にしてください。

JSONをVolleyで解析表示する | JSON Volley Google Maps Geocoding API | Android
JSONとは 地図の住所情報や、天気の情報をインターネットから取得したい場合はJSONデータを扱います。 例えば、東京都庁についてのGoogle Maps Geocoding API 情報を取得したければ を表示します。結果として、 { "results" : [ { "address_components" : [ ...

前準備として、placeAPIを有効化したAPI_KEYは事前に用意してください。

今回はデータについていわゆるカプセル化を行って管理をします。

googlePlaceAPIでは以下のようなデータを取得することができます。

PlaceAPIのJSONデータの概要

西新宿の日本興亜損保ビルを中心とし、ATMについて検索をかけた結果です。

https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=35.6926771341691,139.696091003716&radius=1000&type=atm&language=ja&key=YOUR_API_KEY
{
   "html_attributions" : [],
   "next_page_token" : "CqQCGQEAAP89vpuZK-aK4TRM2J_fFZgFVNqS16IZSY925f9PRNB4trpcgrj4MXWUlFcoXDlYnZIdJMWZLcWEq_DcumWsqWUw4uUDFXnWc1WT6zXZUYS3JarLnMZfxmxtAGTSNcVgd3v3CTk922ScHZYRmfkNrDw8neJApUjODFCgVvYd1cTgt5ZlTKz9bXIBPTmB2bPASmZcbmjFBm1ood3NSOfnBCI9QEBXTi8nzz77eXT2_yDJelSdzv358bxi5yd0PRQLwjH03ZGSJsIMKkHbhz4slajmuPewnByKT2eJatjLD_L_oZtFqXiw0Q-R97FGqxemxMt5tqAAsyZU2u2FwPSMEsp3Kw38UJEOKR4Ogy9kGspWjkBAYzMXMUMNByBHdx0TFxIQGF0hZLt5v7o4VBU9UF_vaBoUar7SScS-2P0oopbb75rQ8iJ_Fp8",
   "results" : [
      {
         "geometry" : {
            "location" : {
               "lat" : 35.6909271,
               "lng" : 139.6970882
            },
            "viewport" : {
// 略
            }
         },
         "icon" : "https://maps.gstatic.com/mapfiles/place_api/icons/bank_dollar-71.png",
         "id" : "1153521cf0b0c1296be0295704accab2f6d6930b",
         "name" : "三菱東京UFJ銀行 新宿中央支店",
         "opening_hours" : {
            "open_now" : false,
            "weekday_text" : []
         },
         "photos" : [
            {
// 略
            }
         ],
         "place_id" : "ChIJaT9ZpdaMGGARVrldL8-_2rI",
         "rating" : 3.5,
         "reference" : "CmRSAAAA2oBF2YmyiFo72MQCj7j8mSR99tXfJuQ-QYodmO8GKYFYipr3zP2ndrR4yH50GvSFNJA4K1CUnjZ6OI8MthYK0tA06XUDHhrgEJ6g4aEy_kd36Hs9erYk42S_eXVvLkT6EhBhSu8VliI5Mmk0q8jWXhF_GhSsJPg5HkFIPclkscRPVJB6GCKu6Q",
         "scope" : "GOOGLE",
         "types" : [ "bank", "atm", "finance", "point_of_interest", "establishment" ],
         "vicinity" : "新宿区西新宿1丁目8−1"
      },
      {
         "geometry" : { //以下略

合計で20件表示されます。

データのカプセル化

今回取得する情報は

・location(緯度経度)

・name(名称)

・open_now(現在開業中かどうか(信用性は?))

・vicinity(住所)

とします。それではカプセル化します。

public class JsonItem {
    private LatLng latLng;
    private String nameString;
    private int openFlag;
    private String addressString;

    public JsonItem(LatLng latLng,String  nameString,
                    int openFlag,String addressString){
        this.latLng = latLng;
        this.nameString = nameString;
        this.openFlag = openFlag;
        this.addressString = addressString;
    }
    public LatLng getLatLng() {
        return latLng;
    }
    public void setLatLng(LatLng latLng) {
        this.latLng = latLng;
    }
    public String getNameString() {
        return nameString;
    }
    public void setNameString(String nameString) {
        this.nameString = nameString;
    }
    public int getOpenFlag() {
        return openFlag;
    }
    public void setOpenFlag(int openFlag) {
        this.openFlag = openFlag;
    }
    public String getAddressString() {
        return addressString;
    }
    public void setAddressString(String addressString) {
        this.addressString = addressString;
    }
}

とします。openFlagがbooleanでない理由はこの値には[開店中、閉店中、データなし]の3種類があるためです。

取得

それでは実際に取得します。事前にVolleyの準備を行ってください。(当ページの最初にあるリンク参照)

setJsonListというメソッドを作ります。hereLLは検索座標、mは範囲(メートル)、typeArrayは取得するタイプ(ATMなど)を配列として渡します。

タイプについてはこちらを参照

Place Types  |  Places API  |  Google for Developers

タイプを2つ入れれば40この値が入ることになります。

private void setJsonList(LatLng hereLL,int m,String[] typeArray){
   final List<JsonItem> childItem = new ArrayList<JsonItem>();
   String API = getResources().getString(R.string.google_maps_key);
   double centerLat = hereLL.latitude;
   double centerLng = hereLL.longitude;
   for(int j=0 ; j<typeArray.length ; j++){
//指定タイプごとにurlを用意します。2つであれば2回実行することになります。
      final String typeString = typeArray[j];
      String addressUrl = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location="+centerLat+","+centerLng+"&radius="+m+"&type="+typeString+"&language="+language+"&key="+API;
      JsonObjectRequest movieReq = new JsonObjectRequest(Request.Method.GET, addressUrl, null, new Response.Listener<JSONObject>() {
      @Override
      public void onResponse(JSONObject response) {
           try {
                for(int i = 0; i<response.getJSONArray("results").length() ; i++) {
                    LatLng latLng = new LatLng(
                            Double.parseDouble(response.getJSONArray("results")
                           .getJSONObject(i).getJSONObject("geometry")
                           .getJSONObject("location").getString("lat"))
                            ,Double.parseDouble(response.getJSONArray("results")
                           .getJSONObject(i).getJSONObject("geometry")
                          .getJSONObject("location").getString("lng"))
                    );
/*
LatLngで扱いますから取得した緯度、経度をLatLngとします。
*/
                    int openFlag;
                    if(response.getJSONArray("results").getJSONObject(i)
                       .has("opening_hours")){
                         String openFlagString = response.getJSONArray("results").getJSONObject(i).getJSONObject("opening_hours").getString("open_now");
                         if (openFlagString.equals("true")) openFlag = 0;
                         else openFlag = 1;
                    }else{
                         openFlag = -1;
                    }
/*
opening_hours自体が存在するかどうかhas()で確認を行い、値を取得します。
true,falseを取得するわけですがStringですのでequalsで判定し、trueで0としました。
has()がfalse、つまり存在しない場合は-1とします。
レーティング情報についても同様に存在判定を行います。存在しない場合は同様に-1とします
*/
                    float ratingFloat;
                    if(response.getJSONArray("results").getJSONObject(i)
            .has("rating")){
                         ratingFloat = Float.parseFloat(response.getJSONArray("results").getJSONObject(i).getString("rating"));
                    }else{
                        ratingFloat = -1;
                    }
/*
LIST<JsonItem>のchildItemに値を入れていきます。
*/
                    childItem.add(new JsonItem(
                         latLng
                         , response.getJSONArray("results").getJSONObject(i)
                           .getString("name")
                         , openFlag
                         , response.getJSONArray("results").getJSONObject(i)
                           .getString("vicinity")
                    ));
                    int nowNumber = childItem.size()-1;
//現時点でのchildItemの最後の値を取得するため、nowNumberを用意
//マーカーを地図にセットしていきます。
                    marker = mMap.addMarker(new MarkerOptions()
                             .position(childItem.get(nowNumber).getLatLng())
                             .icon(BitmapDescriptorFactory
                                  .defaultMarker(BitmapDescriptorFactory.HUE_YELLOW))
                             .title(childItem.get(nowNumber).getNameString())
                             .snippet(childItem.get(nowNumber).getAddressString()));
                    mMarker.add(marker);
                }
            } catch (JSONException e) {
                 Log.d("Log0",e.getMessage());
            }
        }
      },
      new Response.ErrorListener() {
              @Override
              public void onErrorResponse(VolleyError error) {
                     VolleyLog.d("Log0", "Error: " + error.getMessage());
               }
      });
  AppController.getInstance().addToRequestQueue(movieReq);
  }
}

非同期処理ですから結果を表示する際にはonResponse内に記述しました。

また、冒頭で以下のように定義を行っています。

private GoogleMap mMap;
private CameraPosition cameraPosition;
private String language="JA";
private Marker marker;
private java.util.Set<Marker> mMarker = new java.util.HashSet<>();

実はさほど難しいことではないのですが、placeAPIには回数制限(といってもクレジットカードでの確認を行えば一日15万件)がありますので、マップが動くたびに取得するような方法にしてしまいますとあっという間に上限になってしまうかもしれませんし、動作自体が非常に重くなります。その点は十分ご注意ください。

実装する際はonMapReady()に

String[] placeTypeArray = {"atm","convenience_store"};
setJsonList(mMap.getCameraPosition().target,1000,placeTypeArray);

という具合となります。

マーカーの詳しい扱い方については以下の記事を参考にしてください

googleMap第3回 マークと直線 | Marker and Polyline | Android
AndroidでGoogleMapアプリ作成 第1回 表示 第2回 表示形式 衛星、地図、地形図 第3回 マーカーと直線 第4回 googleMapのエラー 第5回 PlaceAPIとマーカーのセット 第6回 現在地 GPSの実装 第7回 トラッキング 第8回 様々な技法 引き続き前回と同じプロジェクトを利用します。 ...