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 full-size slide

  2. CYRILMOTTIER
    @

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  5. 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 full-size slide

  6. I started to do some quick
    USER TESTING

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  15. GOOGLE MAPS
    ANDROID API V2
    TO THE RESCUE

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  18. Introducing
    MAPS API V2
    1

    View full-size slide

  19. v1 vs v2
    Deprecated

    View full-size slide

  20. EXTREMELY
    STRAIGHTFORWARD
    A P I

    View full-size slide

  21. 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 full-size slide

  22. 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 full-size slide

  23. 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 full-size slide

  24. Drawing shapes on MapView
    3POSSIBLE
    SHAPES

    View full-size slide

  25. Drawing shapes on MapView
    3POSSIBLE
    SHAPES
    Polyline

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  28. 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 full-size slide

  29. 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 full-size slide

  30. 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 full-size slide

  31. Deep dive into
    THE INTERNALS
    2

    View full-size slide

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

    View full-size slide

  33. YOUR APP
    Maps API

    View full-size slide

  34. GMS SERVICE
    YOUR APP
    Maps API

    View full-size slide

  35. GMS SERVICE
    YOUR APP
    Maps API

    View full-size slide

  36. GMS SERVICE
    YOUR APP
    Maps API

    PLAY STORE

    View full-size slide

  37. EVERYTHING IS PARCELABLE
    EVERYTHING
    EVERYTHING
    EVERYTHING
    EVERYTHING
    EVERYTHING
    EVERYTHING

    View full-size slide

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

    View full-size slide

  39. A VIEW
    ANOTHER
    MAY HIDE

    View full-size slide

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

    View full-size slide

  41. TextureView
    API 16+
    SurfaceView
    API 15-

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  45. Google Maps Android API v2
    TIPS AND TRICKS
    3

    View full-size slide

  46. Attaching information to Markers

    View full-size slide

  47. Attaching information to Markers

    View full-size slide

  48. Attaching information to Markers

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  51. 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 full-size slide

  52. 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 full-size slide

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

    View full-size slide

  54. 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 full-size slide

  55. Animate state transitions

    View full-size slide

  56. Animate state transitions

    View full-size slide

  57. Animate state transitions

    View full-size slide

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

    View full-size slide

  59. Do it
    ON YOUR OWN!
    SOLUTION

    View full-size slide

  60. 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 full-size slide

  61. 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 full-size slide

  62. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  65. Thank you!
    @cyrilmottier cyrilmottier.com
    ˒

    View full-size slide

  66. 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 full-size slide