この記事でGoogleMapを導入したので同じMap系APIのGoogle Place API for Androidを試してみました。
Google Place API for Androidでできること
このAPIでは以下の機能が利用できるそうです。
- 今いる(もしくはさっきまでいた)と思われる場所を取得する
- 場所の情報(住所や説明文等)を取得する
- Googleが用意した場所をハイライトしたマップの表示
ここでいう「場所」は、施設や商店、観光地等を指すようです。
使用する上での注意
ドキュメントに記載されていますが制限があります。
細かい点はドキュメントを参照してもらいたいですが大きくは4点です。
- 使用回数に制限
- 場所の情報はすべてを改変なしに表示する
- Googleからの提供という表示をする(画像が用意されているのでそれをそのまま表示する)
- このAPIでは指定の座標の周辺の施設の検索は出来ません
最後の4点目はこのAPIではなくGoogle Places API Web Serviceを利用します。
APIの利用前に
このAPIではGoogle Map APIと同様にGoogle Play Servicesの設定と、APIの有効化・APIキーのマニフェストへの設定が必要です。
また、パーミッションとして、ACCESS_FINE_LOCATIONが必要です。
このあたりは以前の記事を参照してください。
今いる場所を取得する
ではこのAPIを利用して今いる場所を取得します。
このAPIを利用するためにはGoogleApiClientが必要です。
GoogleApiClientを設定する
まず、GoogleApiClient.Builderを利用してインスタンスを生成します。
GoogleApiClient googleApiClient = new GoogleApiClient .Builder(context) .addApi(Places.GEO_DATA_API) .addApi(Places.PLACE_DETECTION_API) .addConnectionCallbacks(callback) .addOnConnectionFailedListener(callback) .build(); googleApiClient.connect(); // アプリ終了時 googleApiClient.disconnect();
BuilderをnewしてaddApiにGEO_DATA_APIとPLACE_DETECTION_APIを指定します。
Builderの引数のcontextはActivityで大丈夫です。
connectメソッドでGoogleと通信が行われ、各種APIが利用可能になります。
また、この通信の成否がBuilderに指定したcallbackに返ってきます。
コールバックは以下の通りです。
public class Callback implements GoogleApiClient.ConnectionCallbacks ,GoogleApiClient.OnConnectionFailedListener { @Override public void onConnected( Bundle bundle ) { Log.d("Test", "成功"); // これ以後にAPI関連の処理を行う } @Override public void onConnectionSuspended( int i ) { Log.d("Test", "中断"); } @Override public void onConnectionFailed( ConnectionResult connectionResult ) { Log.d("Test", "失敗"); } }
これを踏まえてActivityの実装例です。
public class Main2Activity extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks ,GoogleApiClient.OnConnectionFailedListener { private GoogleApiClient googleApiClient_; @Override protected void onCreate( Bundle savedInstanceState ) { super.onCreate( savedInstanceState ); googleApiClient_ = new GoogleApiClient .Builder(this) .addApi(Places.GEO_DATA_API) .addApi(Places.PLACE_DETECTION_API) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .build(); } @Override protected void onStart() { super.onStart(); googleApiClient_.connect(); } @Override protected void onStop() { googleApiClient_.disconnect(); super.onStop(); } @Override public void onConnected( Bundle bundle ) { // 成功 } @Override public void onConnectionSuspended( int i ) { Log.d("Test", "中断"); } @Override public void onConnectionFailed( ConnectionResult connectionResult ) { Log.d("Test", "失敗"); } }
PlaceDetectionApiを使う
では、肝心の現在地を取得するAPIを利用します。これはPlaceDetectionApiという名前です。
上述のとおりGoogleApiClientの通信成功あとに処理を記述します。
@Override public void onConnected( Bundle bundle ) { PendingResult<PlaceLikelihoodBuffer> result = Places.PlaceDetectionApi .getCurrentPlace( googleApiClient_, null ); result.setResultCallback( new ResultCallback<PlaceLikelihoodBuffer>() { @Override public void onResult( PlaceLikelihoodBuffer likelyPlaces ) { for ( PlaceLikelihood placeLikelihood : likelyPlaces ) { Log.i("PickerTest", String.format( "Place '%s' has likelihood: %g", placeLikelihood.getPlace().getName(), placeLikelihood.getLikelihood()) ); } likelyPlaces.release(); } }); }
Googleのサンプルそのままですが…
PlaceDetectionApi.getCurrentPlaceで現在地の取得を行います。
これは非同期処理であるため、返り値はPendingResultです。処理が完了したら、ResultCallbackが呼び出されます。
結果はPlaceLikelihoodBufferというPlaceLikelihoodの配列で取得できます。
現在地の取得に失敗したり等、場合によっては中身が空の時もあるようです。
また、使用が終わったらreleaseメソッドを呼ばなければメモリリークが発生します。
結果について
このAPIの結果はその人が今いる、もしくは直前までいた、と思われる場所です。
どの程度結果が正しいかはgetLikelihoodメソッドで確率が取得できますが、あくまで推測で確実にそこにいるとは限りません。
また、前述とおり取得できない場合もありますので、例外処理は必要でしょう。
自宅で実行したら、自宅近辺数100m程の飲食店や公園なんかが取得できましたが、場所としてマップに登録されているものがすべて取得出来ているわけではありませんでした。
このAPIはその人のいる場所を取得するのが目的なので、周囲の施設に取得は厳しそうです。
Place Pickerを表示する
この機能ではPlace Pickerと呼ばれる、現在地とその周辺の施設をマークしたマップを表示できます。
ただし、Googleが用意したものをそのまま使うくらいで通常のマップと違いあまりカスタマイズは出来ません。
概要
このAPIはGoogleが専用の画面を用意しておりカスタマイズはほぼ無理です。テーマが設定できるのでそれに合わせて色が変わる程度です。
実行すると専用マップが表示され、ユーザーが場所のマークを選択するか、戻ることでActivityに結果が返ってきます。
実装
超楽です。
public class Main2Activity extends AppCompatActivity { private final int PLACE_PICKER_REQUEST = 1; @Override protected void onCreate( Bundle savedInstanceState ) { super.onCreate( savedInstanceState ); PlacePicker.IntentBuilder builder = new PlacePicker.IntentBuilder(); Context context = getApplicationContext(); try { startActivityForResult( builder.build( context ), PLACE_PICKER_REQUEST ); } catch ( GooglePlayServicesRepairableException e ) { Log.d( "PickerTest", e.toString() ); } catch ( GooglePlayServicesNotAvailableException e ) { Log.d( "PickerTest", e.toString() ); } } @Override protected void onActivityResult( int requestCode, int resultCode, Intent data ) { super.onActivityResult( requestCode, resultCode, data ); if ( requestCode == PLACE_PICKER_REQUEST ) { if ( resultCode == RESULT_OK ) { Place place = PlacePicker.getPlace( data, this ); String toastMsg = String.format( "Place: %s/%s", place.getName(), place.getAddress() ); Toast.makeText( this, toastMsg, Toast.LENGTH_LONG ).show(); } else { Toast.makeText( this, "失敗:" + requestCode, Toast.LENGTH_LONG ).show(); } } } }
これもGoogleのサンプル大体そのままです。
startActivityで別画面を起動して、その結果をonActivityResultで受けるだけです。
startActivityするとGoogleが用意した専用マップが表示されます。これは先ほど書いた通り現在地とその周辺の場所がマークされたマップです。下側には選択中の場所の情報が表示されています。
戻る、もしくは選択中の場所を決定するとonActivityResultが返ってきます。
resultCodeでキャンセルされたのか、場所が選択されたのかが判別できます。
(startActivityするとGPSの使用の確認のダイアログも自動で出ます。)