Android で LocationManager と MapView を連携させる
Android で Google Map を使ったアプリを作成しようとしたのですが、ライブラリに癖があって結構苦労しました。そこで LocationManager を使って MapView(Google Map) 上に位置情報を表示させる簡単なサンプルプログラムを作成してみました。
サンプルプログラムの機能は以下です。
- 位置情報取得
- 地図にピンを描画
- ピンをタップすると取得した位置情報を表示
事前準備
まずプロジェクトのビルドターゲットを Google APIs ライブラリに変更します。そのあとで Google Map 用の API Key を用意します。
なお Android で Google Map を使うための事前準備に関してこちらの記事がとても参考になりました。
レイアウト XML
Activity で直接 MapView のインスタンスを作成して画面に配置する方法もありますが今回はレイアウト XML を使って MapView を配置します。
画面構成は以下の通りです。
- 位置情報取得ボタン
- 地図(MapView)
- 位置情報取得時間表示用テキスト
- 緯度経度精度表示用テキスト
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <Button android:id="@+id/button_start" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="位置情報取得" /> <com.google.android.maps.MapView android:id="@+id/map" android:layout_width="fill_parent" android:layout_height="320dip" android:enabled="true" android:clickable="true" android:apiKey="xxxxxxxxxxxxxxxxxxxx" /> <TextView android:id="@+id/text_location_title" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <TextView android:id="@+id/text_location_snippet" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout>
OverLay
地図上に画像を表示させるにはオーバレイという仕組みが必要になります。ItemizedOverlay クラスはこのオーバレイの機能を提供してくれるクラスです。この ItemizedOverlay クラスを拡張した独自オーバレイクラスを作成して、地図上に表示させるピン画像の管理をさせます。
なおピン画像はこちらの記事の画像を使用させていただきました。
public class PinItemizedOverlay extends ItemizedOverlay<OverlayItem> { private List<OverlayItem> items = new ArrayList<OverlayItem>(); public PinItemizedOverlay(Drawable defaultMarker) { super(boundCenterBottom(defaultMarker)); } @Override protected OverlayItem createItem(int i) { return items.get(i); } @Override public int size() { return items.size(); } public void addPin(GeoPoint point, String title, String snippet) { items.add(new OverlayItem(point, title, snippet)); populate(); } }
Activity
Activity クラスの実装です。MapView を使う時は MapActivity クラスを拡張します。位置情報取得ボタンを押すと位置情報を取りにいき、その位置にピン画像を表示させます。また地図上のピン画像をタップすると画面下に位置情報が表示されるようにします。
public class MainActivity extends MapActivity implements View.OnClickListener, LocationListener { private LocationManager locationManager; private MapView map; private Button buttonStart; @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main); buttonStart = (Button)findViewById(R.id.button_start); buttonStart.setOnClickListener(this); map = (MapView)findViewById(R.id.map); map.getController().setZoom(18); } @Override protected boolean isRouteDisplayed() { return false; } @Override protected void onStop() { super.onStop(); if (locationManager != null) locationManager.removeUpdates(this); } @Override public void onClick(View view) { locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE); List<String> providers = locationManager.getProviders(true); for (String provider : providers) { locationManager.requestLocationUpdates(provider, 0, 0, this); } buttonStart.setEnabled(false); } @Override public void onLocationChanged(Location location) { addPin(location); locationManager.removeUpdates(MainActivity.this); buttonStart.setEnabled(true); } @Override public void onProviderDisabled(String provider) {} @Override public void onProviderEnabled(String provider) {} @Override public void onStatusChanged(String provider, int status, Bundle extras {} private void addPin(Location location) { GeoPoint point = new GeoPoint((int)(location.getLatitude() * 1E6), (int)(location.getLongitude() * 1E6)); Drawable pin = getResources().getDrawable(R.drawable.pin); PinItemizedOverlay overlay = new PinItemizedOverlay(pin) { @Override protected boolean onTap(int index) { OverlayItem item = (OverlayItem)getItem(index); TextView title = (TextView)findViewById(R.id.text_location_title); title.setText(item.getTitle()); TextView snippet = (TextView)findViewById(R.id.text_location_snippet); snippet.setText(item.getSnippet()); return super.onTap(index); } }; map.getOverlays().add(overlay); overlay.addPin(point, "位置情報:" + new Date(location.getTime()).toLocaleString(), "緯度:" + location.getLatitude() + "経度:" + location.getLongitude() + "\n精度:±" + location.getAccuracy() + "m"); map.getController().setCenter(point); map.invalidate(); } }
addPin メソッドで PinItemizedOverlay クラスの onTap メソッドをオーバライドしているところがポイントです。このようにすることで地図上のオーバレイ画像をタップしたときに画面の内容をいろいろといじることができます。