Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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.

Cyril Mottier

November 11, 2013
Tweet

More Decks by Cyril Mottier

Other Decks in Programming

Transcript

  1. GOOGLE MAPS
    ANDROID API V2
    Getting around with

    View Slide

  2. CYRILMOTTIER
    @

    View Slide

  3. View Slide

  4. View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  8. I started to do some quick
    USER TESTING

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  17. GOOGLE MAPS
    ANDROID API V2
    TO THE RESCUE

    View Slide

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

    View Slide

  19. Map-based apps
    are immersive
    Myapp
    Lorem ipsum amet
    Lorem
    ipsum
    amet
    Lorem ipsum
    mall
    Lorem ipsum
    park
    and that’s awesome :)

    View Slide

  20. Introducing
    MAPS API V2
    1

    View Slide

  21. v1 vs v2

    View Slide

  22. v1 vs v2

    View Slide

  23. v1 vs v2
    Deprecated

    View Slide

  24. EXTREMELY
    STRAIGHTFORWARD
    A P I

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  28. Drawing shapes on MapView
    3POSSIBLE
    SHAPES

    View Slide

  29. Drawing shapes on MapView
    3POSSIBLE
    SHAPES
    Polyline

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  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 }

    View Slide

  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 }

    View Slide

  35. Deep dive into
    THE INTERNALS
    2

    View Slide

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

    View Slide

  37. YOUR APP

    View Slide

  38. YOUR APP
    Maps API

    View Slide

  39. GMS SERVICE
    YOUR APP
    Maps API

    View Slide

  40. GMS SERVICE
    YOUR APP
    Maps API

    View Slide

  41. GMS SERVICE
    YOUR APP
    Maps API

    PLAY STORE

    View Slide

  42. EVERYTHING IS PARCELABLE
    EVERYTHING
    EVERYTHING
    EVERYTHING
    EVERYTHING
    EVERYTHING
    EVERYTHING

    View Slide

  43. View Slide

  44. View Slide

  45. View Slide

  46. … and it may be
    Each call to the API
    is a done through a Binder …
    s l o
    w
    s
    l
    o
    w

    View Slide

  47. A VIEW
    ANOTHER
    MAY HIDE

    View Slide

  48. A VIEW
    ANOTHER
    MAY HIDE
    I.E. THIS IS NOT A (REGULAR) VIEW
    ˒

    View Slide

  49. TextureView
    API 16+
    SurfaceView
    API 15-

    View Slide

  50. No direct Canvas-based rendering
    1
    Only Bitmaps can be rendered
    2
    No Drawable/View automatic refresh
    3

    View Slide

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

    View Slide

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

    View Slide

  53. Google Maps Android API v2
    TIPS AND TRICKS
    3

    View Slide

  54. Attaching information to Markers

    View Slide

  55. Attaching information to Markers

    View Slide

  56. Attaching information to Markers

    View Slide

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

    View Slide

  58. ˒
    Use a MAPPING COLLECTION
    HashMap | LinkedHashMap | ArrayMap
    Map
    NEW
    ˒

    View Slide

  59. 1 private Map mMarkerPositions = new HashMap();!
    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

    View Slide

  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 mLoaderCallbacks =!
    26 new LoaderManager.LoaderCallbacks() {!
    27 @Override!
    28 public Loader onCreateLoader(int id, Bundle args) {!
    29 return new CursorLoader(getBaseContext() /* ... */);!
    30 }!
    31 !
    32 @Override!
    33 public void onLoadFinished(Loader loader, Cursor cursor) {!
    34 mCursor = cursor;!
    35 updatePois();!
    36 }!
    37 !
    38 @Override!
    39 public void onLoaderReset(Loader loader) {!
    40 mCursor = null;!
    41 updatePois();!
    42 }!
    43 };
    Attaching information to Markers

    View Slide

  61. BE
    The “be” attitude
    lazy when possible
    mindful on memory
    nice with users

    View Slide

  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 }

    View Slide

  63. Animate state transitions

    View Slide

  64. Animate state transitions

    View Slide

  65. Animate state transitions

    View Slide

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

    View Slide

  67. Do it
    ON YOUR OWN!
    SOLUTION

    View Slide

  68. 1 public class LatLngEvaluator implements TypeEvaluator {!
    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 }

    View Slide

  69. 1 private static final LatLngEvaluator LAT_LNG_EVALUATOR = new LatLngEvaluator();!
    2 private static final Property 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 !

    View Slide

  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 };!

    View Slide

  71. config.proguard
    -keepclassmembers public class!
    com.google.android.gms.maps.model.Marker {!
    void setPosition(***);!
    *** getPosition();!
    }

    View Slide

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

    View Slide

  73. Thank you!
    @cyrilmottier cyrilmottier.com
    ˒

    View Slide

  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

    View Slide