Load “My Maps” to MapView on Android

You can create maps with point of interests on Goolge Map easily, and then save them to “My Maps” or the new name “My Places” for future use. I created such a map that has Ramen restaurants in Bay Area where I live, so I can bring it up on my Android phone. Although I can view my customized maps by adding a “My Maps” layer to Google Map, I thought it can be useful if I have more control to the map. That’s why I have been playing with MapView and other related API’s, and would like to share my findings here. The source can be found at https://github.com/barryku/SpringCloud/tree/master/AndroidApp/HelloMapView. Here is a screenshot from the running app,

The application is based on HelloMapView sample you can find on http://seveloper.andorid.com with the following additional features,

  1. Parse KML output using Simple XML.
  2. Parse JSON output using Jackson JSON
  3. Add balloon tip on MapView

To get KML or JSON output from your maps or other public maps, just add &output=kml or &output=json at the end of the map URL.  For example, http://maps.google.com/maps/ms?msid=215285050751615203721.0004a6d0191fbec6372b7&msa=0&output=kml will give you the KML output of the map I use in this application. KML only gives me the name and coordinate of my place marks, so I added code to handle JSON output which has a lot more information that can be useful for some applications.

The JSON output unfortunately is not 100% JSON compliant, so I  had to use the following code to work around it,

private void setupJsonOverlays() throws Exception {
	GeoPoint point = null;
	InputStream is = getAssets().open("Ramen_in_Bay_Area.json");
	ObjectMapper mapper = new ObjectMapper();
    mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
    mapper.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true);
	is.skip(9);
	GoogleMap gmap = mapper.readValue(is, GoogleMap.class);
	is.close();
...

The balloon tip uses an approach derived from an excellent tip posted at http://deckjockey.blogspot.com/2010/01/android-baloon-display-on-map.html. I simply created a layout with a TextView and ImageView and use the following code to set it up and then display it whenever users taps on a place marker on the map.

private void setupBalloonLayout() {
	LayoutInflater layoutInflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
	noteBalloon = (BalloonLayout) layoutInflater.inflate(R.layout.balloon, null);

	TextView title = (TextView) noteBalloon.findViewById(R.id.note_txt);
	title.setOnClickListener(new OnClickListener() {

		public void onClick(View v) {
			goPlace();
		}

	});

	ImageView goButton = (ImageView) noteBalloon.findViewById(R.id.go_button);
	goButton.setOnClickListener(new OnClickListener() {

		public void onClick(View v) {
			goPlace();
		}

	});
}

public void doTap(OverlayItem noteOverlay, String txt) {
	mapView.removeView(noteBalloon);
	noteBalloon.setVisibility(View.VISIBLE);
	((TextView)noteBalloon.findViewById(R.id.note_txt)).setText(txt);
	MapController mapController = mapView.getController();
	mapController.animateTo(noteOverlay.getPoint());
	mapView.addView(noteBalloon, new MapView.LayoutParams(12*txt.getBytes().length,55,noteOverlay.getPoint(),MapView.LayoutParams.BOTTOM_CENTER));
}

I used getBytes().length to get the length of my text strings since some of them contain double-byte characters.

The logic of parsing KML and JSON uses Simple and Jackson JSON respectively which really simplifies the parsing. All I had to do is creating those mapping/binding classes accordingly albeit taking some try and error to get them working. The following is the code that works on KML (JSON part is similar),

private void setupKmlOverlays() throws Exception {
	GeoPoint point = null;
	InputStream is = getAssets().open("Ramen_in_Bay_Area.kml");
	Serializer serializer = new Persister();
	KmlRoot kml = serializer.read(KmlRoot.class, is);
	List<Placemark> markers = kml.getDocument().getPlacemarks();
	for (Placemark marker: markers) {
		point = getGeoPointFromCoordiate(marker.getCoordinates());
		Log.d(LOG_TAG, marker.getName());
		itemizedOverlay.addOverlay(new OverlayItem(point, marker.getName(), marker.getDescription()));
	}
}

In order to center the map and display all the place marks, the following code was added,

private void adjustMapZoomCenter(){
	int minLat = Integer.MAX_VALUE;
	int maxLat = Integer.MIN_VALUE;
	int minLon = Integer.MAX_VALUE;
	int maxLon = Integer.MIN_VALUE;

	GeoPoint point = null;
	for (int i=0; i<itemizedOverlay.size(); i++) {
		point = itemizedOverlay.getItem(i).getPoint();
		int lat = point.getLatitudeE6();
		int lon = point.getLongitudeE6();

		maxLat = Math.max(lat, maxLat);
		minLat = Math.min(lat, minLat);
		maxLon = Math.max(lon, maxLon);
		minLon = Math.min(lon, minLon);
	}

	MapController mapController = mapView.getController();
	mapController.zoomToSpan(Math.abs(maxLat - minLat), Math.abs(maxLon
			- minLon));
	mapController.animateTo(new GeoPoint((maxLat + minLat) / 2, (maxLon + minLon) / 2));
	//mapController.animateTo(itemizedOverlay.getCenter()); //may need to call populate() first
}
This entry was posted in Android, Cloud, Google. Bookmark the permalink.

One Response to Load “My Maps” to MapView on Android

  1. Pingback: miguel

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>