Google Mapで現在地を表示 - MapActivity, MapView, MyLocationOverlay, LocationManagerの連携

今回は以前postしたLocationManagerとGoogle Maps APIを使った実装をしてみたいと思います

やりたいこと

    1. MapActivity、MapViewを使用しmapを表示/ちょっとした操作
    2. LocationManagerを使用しUser location情報を取得
    3. MyLocationOverlayを使用しUser location(現在地)をmap上に表示

こんな感じの表示(Iconが現在地)

実装の要点は下記です

1. AndroidManifest.xmlGoogle Maps libraryを使用する為のtagを記載

<uses-library android:name="com.google.android.maps" />

2. AndroidManifest.xmlにInternetとLocation情報にaccessする為のPermissionを記載

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

3. Layout xmlにMapViewを定義し、apiKey attributeを記載

<com.google.android.maps.MapView 
		android:id="@+id/map_view"
		android:layout_width="fill_parent"
		android:layout_height="fill_parent"
		android:clickable="true"
		android:apiKey="自分のGoogle maps api key" />

4. MapActivityを拡張したclassを作成

public class MyMapActivity extends MapActivity{
        @Override
	protected boolean isRouteDisplayed() {
		return false;
	}
}

5. MapView objectを取得し、MapView#setBuiltInZoomControls()をtrueで実行

mMapView = (MapView)findViewById(R.id.map_view);
mMapView.setBuiltInZoomControls(true);

6. MapController objectを取得(MapのAnimationとかの為)

mMapController = mMapView.getController();

7. MyLocationOverlayを取得しMapViewのOverlay listに登録

mMyLocationOverlay = new MyLocationOverlay(this, mMapView);
List<Overlay> overlays = mMapView.getOverlays();
overlays.add(mMyLocationOverlay);

気付いた点です

    • Layout xmlに定義するMapViewのnameはpackage名からきちんと記載(当たり前かな?)

んで実装です

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.android.practice.map"
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="10" />

    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".MyMapActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
		<!--AndroidManifest.xmlにGoogle Maps libraryを使用する為のtagを記載  -->
    	<uses-library android:name="com.google.android.maps" />
    </application>
    <!-- AndroidManifest.xmlにInternetとLocation情報にaccessする為のPermissionを記載 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
</manifest>

Layout xml

<?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"
    >
    <!-- MapViewをLayout xmlに定義 -->
	<!-- apiKeyを記載 -->
	<com.google.android.maps.MapView 
		android:id="@+id/map_view"
		android:layout_width="fill_parent"
		android:layout_height="fill_parent"
		android:clickable="true"
		android:apiKey="自分のGoogle maps api key" />
</LinearLayout>

MapActivityなど

package com.android.practice.map;

import java.util.List;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.MyLocationOverlay;
import com.google.android.maps.Overlay;

import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

//MapActivityを拡張したclassを作成
public class MyMapActivity extends MapActivity {
	
	private static final String TAG = "MyMapActivity";
	private static final boolean DEBUG = true;
	
	private static final String ACTION_LOCATION_UPDATE = "com.android.practice.map.ACTION_LOCATION_UPDATE";
	
	private MapController mMapController;
	private MapView mMapView;
	private MyLocationOverlay mMyLocationOverlay;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        initMapSet();
    }
    
	@Override
	protected void onResume() {
		super.onResume();
		setOverlays();
		setIntentFilterToReceiver();
		requestLocationUpdates();
	}
    
	@Override
	protected void onPause() {
		super.onPause();
		resetOverlays();
		removeUpdates();
	}
	
	@Override
	protected void onDestroy() {
		super.onDestroy();
	}

	@Override
	protected boolean isRouteDisplayed() {
		return false;
	}
	
	private void initMapSet(){
		//MapView objectの取得
        mMapView = (MapView)findViewById(R.id.map_view);
        //MapView#setBuiltInZoomControl()でZoom controlをbuilt-in moduleに任せる
        mMapView.setBuiltInZoomControls(true);
        //MapController objectを取得
        mMapController = mMapView.getController();
	}
	
	private void setOverlays(){
        //User location表示用のMyLocationOverlay objectを取得
		mMyLocationOverlay = new MyLocationOverlay(this, mMapView);
		//初めてLocation情報を受け取った時の処理を記載
		//試しにそのLocationにanimationで移動し、zoom levelを19に変更
        mMyLocationOverlay.runOnFirstFix(new Runnable(){
        	public void run(){
        		GeoPoint gp = mMyLocationOverlay.getMyLocation();
				mMapController.animateTo(gp);
				mMapController.setZoom(19);
        	}
        });
        //LocationManagerからのLocation update取得
		mMyLocationOverlay.enableMyLocation();
		
		//overlayのlistにMyLocationOverlayを登録
        List<Overlay> overlays = mMapView.getOverlays();
        overlays.add(mMyLocationOverlay);
	}
	
	private void resetOverlays(){
        //LocationManagerからのLocation update情報を取得をcancel
		mMyLocationOverlay.disableMyLocation();
		
		//overlayのlistからMyLocationOverlayを削除
		List<Overlay> overlays = mMapView.getOverlays();
        overlays.remove(mMyLocationOverlay);
	}
	
	private void setIntentFilterToReceiver(){
		final IntentFilter filter = new IntentFilter();
    	filter.addAction(ACTION_LOCATION_UPDATE);
    	registerReceiver(new LocationUpdateReceiver(), filter);
	}
	
	private void requestLocationUpdates(){
		final PendingIntent requestLocation = getRequestLocationIntent(this);
		LocationManager lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
        for(String providerName: lm.getAllProviders()){
			if(lm.isProviderEnabled(providerName)){
				lm.requestLocationUpdates(providerName, 0, 0, requestLocation);
				if(DEBUG)Log.d(TAG, "Provider: " + providerName);
			}
		}
	}
	
	private PendingIntent getRequestLocationIntent(Context context){
		return PendingIntent.getBroadcast(context, 0, new Intent(ACTION_LOCATION_UPDATE), 
				PendingIntent.FLAG_UPDATE_CURRENT);
	}
	
	private void removeUpdates(){
    	final PendingIntent requestLocation = getRequestLocationIntent(this);
		LocationManager lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
		lm.removeUpdates(requestLocation);
		if(DEBUG)Toast.makeText(this, "Remove update", Toast.LENGTH_SHORT).show();    	
    }
	
	public class LocationUpdateReceiver extends BroadcastReceiver{
		
		@Override
		public void onReceive(Context context, Intent intent) {
			String action = intent.getAction();
			if(action == null){
				return;
			}
			if(action.equals(ACTION_LOCATION_UPDATE)){
				//Location情報を取得
				Location loc = (Location)intent.getExtras().get(LocationManager.KEY_LOCATION_CHANGED);
				//試しにMapControllerで現在値に移動する
				mMapController.animateTo(new GeoPoint((int)(loc.getLatitude() * 1E6), (int)(loc.getLongitude() * 1E6)));
				if(DEBUG)Toast.makeText(context, "latitude:" + loc.getLatitude() + "\nlongitude:" + loc.getLongitude(), Toast.LENGTH_SHORT).show();
			}
		}
		
	}

とこんな感じです。簡単にUser location(現在地)情報がGoogle map上に表示されたり、そこまでAnimationして移動したり出来るという事が分かります。ただ、MyLocationOverlayだと、その他、出来ることが限られて来るかなと思いますので今度は大元のOverlayやItemizedOverlayを試しに使用してみたいなと思います

HashTag #Java, #Android, #MapActivity, #MapView, #MapController, #MyLocationOverlay, #LocationManager, #Location, #GeoPoint, #BroadcastReceiver, #IntentFilter