Pro Yearly is on sale from $80 to $50! »

Getting around with Google Maps Android API v2

Getting around with Google Maps Android API v2

As part of the Google Play services - a platform that offers a better integration with Google products - Google recently released perhaps one of the most frequently requested upgrade: the Google Maps Android API v2. This new framework allows you to embed standard or customized maps directly in your application. Now Google Maps Android API v2 lets you leverage Google's beautiful new vector based maps.

In this session, we will learn about the new API and features introduced with Google Maps Android API v2 and how to start visualizing information geographically within your applications.

E9bf8f6d5480ea2a2623df7dccfd1f70?s=128

Cyril Mottier

November 11, 2013
Tweet

Transcript

  1. GOOGLE MAPS ANDROID API V2 Getting around with

  2. CYRILMOTTIER @

  3. None
  4. None
  5. I once made a LOVELY & GOOD-LOOKING mobile app

  6. I once made a LOVELY & GOOD-LOOKING mobile app

  7. IT
 LOOKED LIKE THIS Myapp 1001 - Lorem ipsum amet

    Lorem ipsum amet 1002 - Lorem ipsum amet Lorem ipsum amet 1003 - Lorem ipsum amet Lorem ipsum amet 1004 - Lorem ipsum amet Lorem ipsum amet 1005 - Lorem ipsum amet Lorem ipsum amet 1006 - Lorem ipsum amet Lorem ipsum amet 1007 - Lorem ipsum amet Lorem ipsum amet 1008 - Lorem ipsum amet Lorem ipsum amet 1009 - Lorem ipsum amet Lorem ipsum amet
  8. I started to do some quick USER TESTING

  9. “That’s a pretty nice list of thingy things” – John

    Doe
  10. “It sucks” – John Doe’s translator

  11. Lists-based screens are boring and give no geographic context

  12. Maps give the user some clear context on POI LOCATION

  13. Maps give the user some clear context on USER LOCATION

    POI LOCATION
  14. Maps give the user some clear context on DISTANCES USER

    LOCATION POI LOCATION
  15. Maps give the user some clear context on DISTANCE USER

    LOCATION POI LOCATION DIRECTIONS
  16. Maps give the user some clear context on DISTANCES USER

    LOCATION POI LOCATION DIRECTIONS
  17. GOOGLE MAPS ANDROID API V2 TO THE RESCUE

  18. Map-based apps are immersive Myapp Lorem ipsum amet Lorem ipsum

    amet Lorem ipsum mall Lorem ipsum park
  19. Map-based apps are immersive Myapp Lorem ipsum amet Lorem ipsum

    amet Lorem ipsum mall Lorem ipsum park and that’s awesome :)
  20. Introducing MAPS API V2 1

  21. v1 vs v2

  22. v1 vs v2

  23. v1 vs v2 Deprecated

  24. EXTREMELY STRAIGHTFORWARD A P I

  25. 1 public class TestActivity extends FragmentActivity {! 2 private GoogleMap

    mMap;! 3 ! 4 @Override! 5 protected void onCreate(Bundle savedInstanceState) {! 6 super.onCreate(savedInstanceState);! 7 setContentView(R.layout.activity_marker);! 8 setUpMapIfNeeded();! 9 }! 10 ! 11 @Override! 12 protected void onResume() {! 13 super.onResume();! 14 setUpMapIfNeeded();! 15 }! 16 ! 17 private void setUpMapIfNeeded() {! 18 if (mMap == null) {! 19 mMap = ((SupportMapFragment) getSupportFragmentManager().! 20 findFragmentById(R.id.map)).getMap();! 21 if (mMap != null) {! 22 setUpMap();! 23 }! 24 }! 25 }! 26 ! 27 private void setUpMap() { /* TODO */ }! 28 } Initial [Support]MapFragment setup
  26. 1 private static final LatLng LYON = new LatLng(45.764043, 4.835659);!

    2 ! 3 private Marker mMarker;! 4 ! 5 private void setUpMap() {! 6 mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LYON, 6));! 7 ! 8 mMarker = mMap.addMarker(new MarkerOptions().! 9 position(LYON).! 10 title("Lyon").! 11 snippet("City of Lights").! 12 icon(BitmapDescriptorFactory.! 13 defaultMarker(BitmapDescriptorFactory.HUE_RED)));! 14 } Annotating with Markers
  27. 1 private static final LatLng LYON = new LatLng(45.764043, 4.835659);!

    2 ! 3 private Marker mMarker;! 4 ! 5 private void setUpMap() {! 6 mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LYON, 6));! 7 ! 8 mMarker = mMap.addMarker(new MarkerOptions().! 9 position(LYON).! 10 title("Lyon").! 11 snippet("City of Lights").! 12 icon(BitmapDescriptorFactory.! 13 defaultMarker(BitmapDescriptorFactory.HUE_RED)));! 14 } Annotating with Markers
  28. Drawing shapes on MapView 3POSSIBLE SHAPES

  29. Drawing shapes on MapView 3POSSIBLE SHAPES Polyline

  30. Polyline Drawing shapes on MapView 3POSSIBLE SHAPES Polygon |

  31. Polyline | Drawing shapes on MapView 3POSSIBLE SHAPES Circle |

    Polygon
  32. 1 private void setUpMap() {! 2 mMap.addCircle(getCircleOptions(new LatLng(45.8, 4.8), 20000));!

    3 mMap.addCircle(getCircleOptions(new LatLng(46.03, 4.6), 10000));! 4 mMap.addCircle(getCircleOptions(new LatLng(46.03, 5), 10000));! 5 }! 6 ! 7 private CircleOptions mCircleOptions = new CircleOptions();! 8 ! 9 private CircleOptions getCircleOptions(LatLng center,! 10 double radius) {! 11 final float w = 4 * getResources().getDisplayMetrics().density;! 12 return mCircleOptions.! 13 center(center).! 14 radius(radius).! 15 strokeWidth(w).! 16 strokeColor(Color.RED);! 17 } Drawing shapes on MapView
  33. Overlaying map with GroundOverlay 1 private static final LatLng NEWARK

    = new LatLng(40.71408, -74.22869);! 2 ! 3 private void setUpMap() {! 4 mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(NEWARK, 11));! 5 ! 6 mMap.addGroundOverlay(new GroundOverlayOptions().! 7 image(BitmapDescriptorFactory.! 8 fromResource(R.drawable.newark_1922)).! 9 anchor(0, 1).! 10 position(NEWARK, 8600f, 6500f));! 11 }
  34. Rendering custom tiles with TileOverlay 1 private static final String

    MOON_MAP_URL_FORMAT =! 2 "http://www.google.moon/bw/%d/%d/%d.jpg";! 3 ! 4 private void setUpMap() {! 5 mMap.setMapType(GoogleMap.MAP_TYPE_NONE);! 6 ! 7 TileProvider tileProvider = new UrlTileProvider(256, 256) {! 8 @Override! 9 public synchronized URL getTileUrl(int x, int y, int zoom) {! 10 String s = String.format(Locale.US,! 11 MOON_MAP_URL_FORMAT, x, y, zoom);! 12 try {! 13 return new URL(s);! 14 } catch (MalformedURLException e) {! 15 throw new AssertionError(e);! 16 }! 17 }! 18 };! 19 ! 20 mMap.addTileOverlay(new TileOverlayOptions().! 21 tileProvider(tileProvider));! 22 }
  35. Deep dive into THE INTERNALS 2

  36. Google Maps Android API v2 is part of Google Play

    Services
  37. YOUR APP

  38. YOUR APP Maps API

  39. GMS SERVICE YOUR APP Maps API

  40. GMS SERVICE YOUR APP Maps API

  41. GMS SERVICE YOUR APP Maps API ‘ PLAY STORE

  42. EVERYTHING IS PARCELABLE EVERYTHING EVERYTHING EVERYTHING EVERYTHING EVERYTHING EVERYTHING

  43. None
  44. None
  45. None
  46. … and it may be Each call to the API

    is a done through a Binder … s l o w s l o w
  47. A VIEW ANOTHER MAY HIDE

  48. A VIEW ANOTHER MAY HIDE I.E. THIS IS NOT A

    (REGULAR) VIEW ˒
  49. TextureView API 16+ SurfaceView API 15-

  50. No direct Canvas-based rendering 1 Only Bitmaps can be rendered

    2 No Drawable/View automatic refresh 3
  51. You must be on the UI THREAD WHEN CALLING ANY

    METHOD ON any VIEW
  52. You must be on the UI THREAD WHEN CALLING ANY

    METHOD ON any GOOGLEMAP
  53. Google Maps Android API v2 TIPS AND TRICKS 3

  54. Attaching information to Markers

  55. Attaching information to Markers

  56. Attaching information to Markers

  57. ˒ Use a MAPPING COLLECTION HashMap | LinkedHashMap | ArrayMap

    Map<K, V> ˒
  58. ˒ Use a MAPPING COLLECTION HashMap | LinkedHashMap | ArrayMap

    Map<K, V> NEW ˒
  59. 1 private Map<Marker, Integer> mMarkerPositions = new HashMap<Marker, Integer>();! 2

    private Cursor mCursor;! 3 ! 4 private void setUpMap() {! 5 updatePois();! 6 }! 7 ! 8 private void updatePois() {! 9 mMarkerPositions.clear();! 10 if (mMap != null) {! 11 mMap.clear();! 12 if (mCursor != null) {! 13 final MarkerOptions markerOptions = new MarkerOptions();! 14 while (mCursor.moveToNext()) {! 15 final Marker marker = mMap.addMarker(markerOptions.! 16 position(new LatLng(! 17 mCursor.getDouble(PoisQuery.LAT),! 18 mCursor.getDouble(PoisQuery.LNG))));! 19 mMarkerPositions.put(marker, mCursor.getPosition());! 20 }! 21 }! 22 }! 23 }! Attaching information to Markers
  60. 17 mCursor.getDouble(PoisQuery.LAT),! 18 mCursor.getDouble(PoisQuery.LNG))));! 19 mMarkerPositions.put(marker, mCursor.getPosition());! 20 }! 21

    }! 22 }! 23 }! 24 ! 25 private final LoaderManager.LoaderCallbacks<Cursor> mLoaderCallbacks =! 26 new LoaderManager.LoaderCallbacks<Cursor>() {! 27 @Override! 28 public Loader<Cursor> onCreateLoader(int id, Bundle args) {! 29 return new CursorLoader(getBaseContext() /* ... */);! 30 }! 31 ! 32 @Override! 33 public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {! 34 mCursor = cursor;! 35 updatePois();! 36 }! 37 ! 38 @Override! 39 public void onLoaderReset(Loader<Cursor> loader) {! 40 mCursor = null;! 41 updatePois();! 42 }! 43 }; Attaching information to Markers
  61. BE The “be” attitude lazy when possible mindful on memory

    nice with users
  62. 1 private void setUpMap() {! 2 mMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {! 3

    @Override! 4 public View getInfoWindow(Marker marker) {! 5 return null;! 6 }! 7 ! 8 @Override! 9 public View getInfoContents(Marker marker) {! 10 Integer position = mMarkerPositions.get(marker);! 11 if (position == null || mCursor == null) {! 12 return null;! 13 }! 14 mCursor.moveToPosition(position);! 15 marker.setTitle(mCursor.getString(PoisQuery.TITLE));! 16 marker.setSnippet(mCursor.getString(PoisQuery.SUBTITLE));! 17 return null;! 18 }! 19 });! 20 //...! 21 }
  63. Animate state transitions

  64. Animate state transitions

  65. Animate state transitions

  66. GOOGLE MAPS ANDROID API V2 No actual animation support in

  67. Do it ON YOUR OWN! SOLUTION

  68. 1 public class LatLngEvaluator implements TypeEvaluator<LatLng> {! 2 ! 3

    @Override! 4 public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) {! 5 double endValueLng = endValue.longitude;! 6 ! 7 // Take the shortest path across the 180th meridian.! 8 double lngDelta = startValue.longitude - endValue.longitude;! 9 if (Math.abs(lngDelta) >= 180) {! 10 endValueLng = endValue.longitude + Math.signum(lngDelta) * 360;! 11 }! 12 ! 13 double newLat = eval(fraction, startValue.latitude, endValue.latitude);! 14 double newLng = eval(fraction, startValue.longitude, endValueLng);! 15 return new LatLng(newLat, newLng);! 16 }! 17 ! 18 private static double eval(float fraction, double startValue, double endValue) {! 19 return startValue + fraction * (endValue - startValue);! 20 }! 21 }
  69. 1 private static final LatLngEvaluator LAT_LNG_EVALUATOR = new LatLngEvaluator();! 2

    private static final Property<Marker, LatLng> MARKER_POSITION_PROPERTY =! 3 Property.of(Marker.class, LatLng.class, "position");! 4 ! 5 private static final LatLng LYON = new LatLng(45.764043, 4.835659);! 6 private static final LatLng PARIS = new LatLng(48.856614, 2.3522219);! 7 ! 8 private LatLng mCurrentDest = LYON;! 9 private Marker mMarker;! 10 private ObjectAnimator mMarkerAnimator;! 11 ! 12 private void setUpMap() {! 13 mMap.setOnMarkerClickListener(mOnMarkerClickListener);! 14 mMarker = mMap.addMarker(new MarkerOptions().position(mCurrentDest));! 15 }! 16 ! 17 ! 18 ! 19 ! 20 ! 21 ! 22 ! 23 !
  70. 19 ! 20 ! 21 ! 22 ! 23 !

    24 ! 25 private final GoogleMap.OnMarkerClickListener mOnMarkerClickListener =! 26 new GoogleMap.OnMarkerClickListener() {! 27 @Override! 28 public boolean onMarkerClick(Marker marker) {! 29 mCurrentDest = mCurrentDest.equals(LYON) ? PARIS : LYON;! 30 if (mMarkerAnimator == null) {! 31 mMarkerAnimator = ObjectAnimator.ofObject(mMarker,! 32 MARKER_POSITION_PROPERTY,! 33 LAT_LNG_EVALUATOR,! 34 mCurrentDest);! 35 } else {! 36 mMarkerAnimator.setObjectValues(mCurrentDest);! 37 }! 38 mMarkerAnimator.start();! 39 return true;! 40 }! 41 };!
  71. config.proguard -keepclassmembers public class! com.google.android.gms.maps.model.Marker {! void setPosition(***);! *** getPosition();!

    }
  72. googlemaps.github.io/android-maps-utils/ Need more?

  73. Thank you! @cyrilmottier cyrilmottier.com ˒

  74. Resources Map Marker by Andrew Onorato Dressed for Iceland by

    Cécile Bernard Moelwynion, Eryri, Cymru by Marc Popletton Badge by Edward Boatman Snail by aLf Fonts Geared Slab Mission Script