NEW RELEASE! Buku best practice Pemrograman Android

24 JAM!! Pintar Pemrograman Android

detil dapat dilihat di klik link halaman ini

Sejak 27 Juli 2012, Maps Google service tidak mengeluarkan data output berupa KML ( isu yang berkembang di beberapa mailist dan forum developer android. Sumber 1, sumber 2 , sumber 3).  Padahal tidak sedikit developer android yang memanfaatkan ouput KML dari Maps Google ini untuk membuat fitur direction pada aplikasinya yang berbasis LBS (Location Based Service). Termasuk penulis sempat mengalami kebingungan karena tiap kali mengakses direction hasilnya selalu failed, padahal secara logika coding sudah tidak ada lagi bugnya.

Ada alternative lain untuk membuat direction, yaitu menggunakan output berupa JSON dari service Maps Google. Semoga postingan ini membantu sahabat omayib di seluruh Tanah Air agar bisa membiat fitur direction.

1. Siapkan project baru
Project name : mapsDirection
package name :  com.android.map.direction
Target device  : Google APIs Level 8

2. Tambahkan komponen maps di layout activity_main.xml seperti dibawah ini

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
 
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:padding="@dimen/padding_medium"
        android:text="@string/hello_world"
        tools:context=".MainActivity" />
 
    <com.google.android.maps.MapView
        android:id="@+id/map_view"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:apiKey="YOUR API KEY"
        android:clickable="true"
        android:enabled="true" />
 
</RelativeLayout>

3. Selanjutnya buat package baru dengan cara klik kanan folder src > new > package. Nama package : direction.json.parser. Dengan demikian Anda mempunyai 2 package dalam satu project (package com.android.map.direction dan package direction.json.parser)

4. Tambahkan 6 class dibawah ini ke dalam package direction.json.parser. Cara membuat new class, klik kanan package direction.json.parser > new > class

public interface Parser {
        public Route parse();
}
package direction.json.parser;
import java.net.URL;
import java.io.IOException;
import java.net.MalformedURLException;
import java.io.InputStream;
 
public class XMLParser {
        // names of the XML tags
        protected static final String MARKERS = "markers";
        protected static final String MARKER = "marker";
 
        protected URL feedUrl;
 
        protected XMLParser(final String feedUrl) {
                try {
                        this.feedUrl = new URL(feedUrl);
                } catch (MalformedURLException e) {
                        //Log.e(e.getMessage(), "XML parser - " + feedUrl);
                }
        }
 
        protected InputStream getInputStream() {
                try {
                        return feedUrl.openConnection().getInputStream();
                } catch (IOException e) {
                        //Log.e(e.getMessage(), "XML parser - " + feedUrl);
                        return null;
                }
        }
}
package direction.json.parser;
import com.google.android.maps.GeoPoint;
 
public class Segment {
        /** Points in this segment. **/
        private GeoPoint start;
        /** Turn instruction to reach next segment. **/
        private String instruction;
        /** Length of segment. **/
        private int length;
        /** Distance covered. **/
        private double distance;
 
        /**
         * Create an empty segment.
         */
 
        public Segment() {
        }
 
        /**
         * Set the turn instruction.
         * @param turn Turn instruction string.
         */
 
        public void setInstruction(final String turn) {
                this.instruction = turn;
        }
 
        /**
         * Get the turn instruction to reach next segment.
         * @return a String of the turn instruction.
         */
 
        public String getInstruction() {
                return instruction;
        }
 
        /**
         * Add a point to this segment.
         * @param point GeoPoint to add.
         */
 
        public void setPoint(final GeoPoint point) {
                start = point;
        }
 
        /** Get the starting point of this
         * segment.
         * @return a GeoPoint
         */
 
        public GeoPoint startPoint() {
                return start;
        }
 
        /** Creates a segment which is a copy of this one.
         * @return a Segment that is a copy of this one.
         */
 
        public Segment copy() {
                final Segment copy = new Segment();
                copy.start = start;
                copy.instruction = instruction;
                copy.length = length;
                copy.distance = distance;
                return copy;
        }
 
        /**
         * @param length the length to set
         */
        public void setLength(final int length) {
                this.length = length;
        }
 
        /**
         * @return the length
         */
        public int getLength() {
                return length;
        }
 
        /**
         * @param distance the distance to set
         */
        public void setDistance(double distance) {
                this.distance = distance;
        }
 
        /**
         * @return the distance
         */
        public double getDistance() {
                return distance;
        }
 
}

 

package direction.json.parser;
import java.util.ArrayList;
import java.util.List;
 
import com.google.android.maps.GeoPoint;
 
public class Route {
        private String name;
        private final List<GeoPoint> points;
        private List<Segment> segments;
        private String copyright;
        private String warning;
        private String country;
        private int length;
        private String polyline;
 
        public Route() {
                points = new ArrayList<GeoPoint>();
                segments = new ArrayList<Segment>();
        }
 
        public void addPoint(final GeoPoint p) {
                points.add(p);
        }
 
        public void addPoints(final List<GeoPoint> points) {
                this.points.addAll(points);
        }
 
        public List<GeoPoint> getPoints() {
                return points;
        }
 
        public void addSegment(final Segment s) {
                segments.add(s);
        }
 
        public List<Segment> getSegments() {
                return segments;
        }
 
        /**
         * @param name the name to set
         */
        public void setName(final String name) {
                this.name = name;
        }
 
        /**
         * @return the name
         */
        public String getName() {
                return name;
        }
 
        /**
         * @param copyright the copyright to set
         */
        public void setCopyright(String copyright) {
                this.copyright = copyright;
        }
 
        /**
         * @return the copyright
         */
        public String getCopyright() {
                return copyright;
        }
 
        /**
         * @param warning the warning to set
         */
        public void setWarning(String warning) {
                this.warning = warning;
        }
 
        /**
         * @return the warning
         */
        public String getWarning() {
                return warning;
        }
 
        /**
         * @param country the country to set
         */
        public void setCountry(String country) {
                this.country = country;
        }
 
        /**
         * @return the country
         */
        public String getCountry() {
                return country;
        }
 
        /**
         * @param length the length to set
         */
        public void setLength(int length) {
                this.length = length;
        }
 
        /**
         * @return the length
         */
        public int getLength() {
                return length;
        }
 
        /**
         * @param polyline the polyline to set
         */
        public void setPolyline(String polyline) {
                this.polyline = polyline;
        }
 
        /**
         * @return the polyline
         */
        public String getPolyline() {
                return polyline;
        }
 
}
package direction.json.parser;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
 
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
 
import android.util.Log;
 
import com.google.android.maps.GeoPoint;
 
public class GoogleParser extends XMLParser implements Parser {
        /** Distance covered. **/
        private int distance;
 
        public GoogleParser(String feedUrl) {
                super(feedUrl);
        }
 
        /**
         * Parses a url pointing to a Google JSON object to a Route object.
         * @return a Route object based on the JSON object.
         */
 
        public Route parse() {
                // turn the stream into a string
                final String result = convertStreamToString(this.getInputStream());
                //Create an empty route
                final Route route = new Route();
                //Create an empty segment
                final Segment segment = new Segment();
                try {
                        //Tranform the string into a json object
                        final JSONObject json = new JSONObject(result);
                        //Get the route object
                        final JSONObject jsonRoute = json.getJSONArray("routes").getJSONObject(0);
                        //Get the leg, only one leg as we don't support waypoints
                        final JSONObject leg = jsonRoute.getJSONArray("legs").getJSONObject(0);
                        //Get the steps for this leg
                        final JSONArray steps = leg.getJSONArray("steps");
                        //Number of steps for use in for loop
                        final int numSteps = steps.length();
                        //Set the name of this route using the start & end addresses
                        route.setName(leg.getString("start_address") + " to " + leg.getString("end_address"));
                        //Get google's copyright notice (tos requirement)
                        route.setCopyright(jsonRoute.getString("copyrights"));
                        //Get the total length of the route.
                        route.setLength(leg.getJSONObject("distance").getInt("value"));
                        //Get any warnings provided (tos requirement)
                        if (!jsonRoute.getJSONArray("warnings").isNull(0)) {
                                route.setWarning(jsonRoute.getJSONArray("warnings").getString(0));
                        }
                        /* Loop through the steps, creating a segment for each one and
                         * decoding any polylines found as we go to add to the route object's
                         * map array. Using an explicit for loop because it is faster!
                         */
                        for (int i = 0; i < numSteps; i++) {
                                //Get the individual step
                                final JSONObject step = steps.getJSONObject(i);
                                //Get the start position for this step and set it on the segment
                                final JSONObject start = step.getJSONObject("start_location");
                                final GeoPoint position = new GeoPoint((int) (start.getDouble("lat")*1E6),
                                        (int) (start.getDouble("lng")*1E6));
                                segment.setPoint(position);
                                //Set the length of this segment in metres
                                final int length = step.getJSONObject("distance").getInt("value");
                                distance += length;
                                segment.setLength(length);
                                segment.setDistance(distance/1000);
                                //Strip html from google directions and set as turn instruction
                                segment.setInstruction(step.getString("html_instructions").replaceAll("<(.*?)*>", ""));
                                //Retrieve & decode this segment's polyline and add it to the route.
                                route.addPoints(decodePolyLine(step.getJSONObject("polyline").getString("points")));
                                //Push a copy of the segment to the route
                                route.addSegment(segment.copy());
                        }
                } catch (JSONException e) {
                        Log.e(e.getMessage(), "Google JSON Parser - " + feedUrl);
                }
                return route;
        }
 
        /**
         * Convert an inputstream to a string.
         * @param input inputstream to convert.
         * @return a String of the inputstream.
         */
 
        private static String convertStreamToString(final InputStream input) {
        final BufferedReader reader = new BufferedReader(new InputStreamReader(input));
        final StringBuilder sBuf = new StringBuilder();
 
        String line = null;
        try {
            while ((line = reader.readLine()) != null) {
                sBuf.append(line);
            }
        } catch (IOException e) {
                Log.e(e.getMessage(), "Google parser, stream2string");
        } finally {
            try {
                input.close();
            } catch (IOException e) {
                Log.e(e.getMessage(), "Google parser, stream2string");
            }
        }
        return sBuf.toString();
    }
 
        /**
         * Decode a polyline string into a list of GeoPoints.
         * @param poly polyline encoded string to decode.
         * @return the list of GeoPoints represented by this polystring.
         */
 
        private List<GeoPoint> decodePolyLine(final String poly) {
                int len = poly.length();
                int index = 0;
                List<GeoPoint> decoded = new ArrayList<GeoPoint>();
                int lat = 0;
                int lng = 0;
 
                while (index < len) {
                int b;
                int shift = 0;
                int result = 0;
                do {
                        b = poly.charAt(index++) - 63;
                        result |= (b & 0x1f) << shift;
                        shift += 5;
                } while (b >= 0x20);
                int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
                lat += dlat;
 
                shift = 0;
                result = 0;
                do {
                        b = poly.charAt(index++) - 63;
                        result |= (b & 0x1f) << shift;
                        shift += 5;
                } while (b >= 0x20);
                        int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
                        lng += dlng;
 
                decoded.add(new GeoPoint(
                        (int) (lat*1E6 / 1E5), (int) (lng*1E6 / 1E5)));
                }
 
                return decoded;
                }
}
package direction.json.parser;
 
import java.util.Iterator;
import java.util.List;
 
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
 
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.Projection;
 
public class RouteOverlay extends Overlay {
        /** GeoPoints representing this routePoints. **/
        private final List<GeoPoint> routePoints;
        /** Colour to paint routePoints. **/
        private int colour;
        /** Alpha setting for route overlay. **/
        private static final int ALPHA = 120;
        /** Stroke width. **/
        private static final float STROKE = 4.5f;
        /** Route path. **/
        private final Path path;
        /** Point to draw with. **/
        private final Point p;
        /** Paint for path. **/
        private final Paint paint;
 
        /**
         * Public constructor.
         *
         * @param route Route object representing the route.
         * @param defaultColour default colour to draw route in.
         */
 
        public RouteOverlay(final Route route, final int defaultColour) {
                super();
                routePoints = route.getPoints();
                colour = defaultColour;
                path = new Path();
                p = new Point();
                paint = new Paint();
        }
 
        @Override
        public final void draw(final Canvas c, final MapView mv,
                        final boolean shadow) {
                super.draw(c, mv, shadow);
 
                paint.setColor(colour);
                paint.setAlpha(ALPHA);
                paint.setAntiAlias(true);
                paint.setStrokeWidth(STROKE);
                paint.setStyle(Paint.Style.STROKE);
 
                redrawPath(mv);
                c.drawPath(path, paint);
        }
 
        /**
         * Set the colour to draw this route's overlay with.
         *
         * @param c  Int representing colour.
         */
        public final void setColour(final int c) {
                colour = c;
        }
 
        /**
         * Clear the route overlay.
         */
        public final void clear() {
                routePoints.clear();
        }
 
        /**
         * Recalculate the path accounting for changes to
         * the projection and routePoints.
         * @param mv MapView the path is drawn to.
         */
 
        private void redrawPath(final MapView mv) {
                final Projection prj = mv.getProjection();
                path.rewind();
                final Iterator<GeoPoint> it = routePoints.iterator();
                prj.toPixels(it.next(), p);
                path.moveTo(p.x, p.y);
                while (it.hasNext()) {
                        prj.toPixels(it.next(), p);
                        path.lineTo(p.x, p.y);
                }
                path.setLastPoint(p.x, p.y);
        }
 
}

5. Sekarang kita pindah ke package com.android.map.direction. Disini kita mempunyai MainActivity.java. Tambahkan method berikut ini kedalam MainActivity.java

private Route directions(final GeoPoint start, final GeoPoint dest) {
		Parser parser;
		final StringBuffer sBuf = new StringBuffer(
				"http://maps.googleapis.com/maps/api/directions/json?");
		sBuf.append("origin=");
		sBuf.append(start.getLatitudeE6() / 1E6);
		sBuf.append(',');
		sBuf.append(start.getLongitudeE6() / 1E6);
		sBuf.append("&destination=");
		sBuf.append(dest.getLatitudeE6() / 1E6);
		sBuf.append(',');
		sBuf.append(dest.getLongitudeE6() / 1E6);
		sBuf.append("&sensor=true&mode=driving");
		parser = new GoogleParser(sBuf.toString());
		Route r = parser.parse();
		return r;
	}

6. Cara mengakses method pada nomor 5 diatas dengan cara menambahkan code berikut ke dalam method oncreate().

GeoPoint gpSolo = new GeoPoint((int) (-7.56229 * 1E6), (int) (110.816517 * 1E6));
	GeoPoint gpJogja = new GeoPoint((int) (-7.824269 * 1E6), (int) (110.364532 * 1E6));
	Route route = directions(gpSolo,gpJogja);
	RouteOverlay routeOverlay = new RouteOverlay(route, Color.BLUE);
	mv.getOverlays().add(routeOverlay);
	mv.getController().animateTo(gpSolo);
	mv.getController().setZoom(15);

7. Dengan demikianclass MainActivity.java secara utuh  untuk mendapatkan direction dari kota Solo menuju Yogyakarta seperti berikut

package com.android.map.direction;
 
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;
 
import direction.json.parser.GoogleParser;
import direction.json.parser.Parser;
import direction.json.parser.Route;
import direction.json.parser.RouteOverlay;
 
import android.os.Bundle;
import android.graphics.Color;
import android.view.Menu;
 
public class MainActivity extends MapActivity {
	MapView mv;
	//solo : -7.56229,110.816517
	//jogja : -7.824269, 110.364532
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
 
		mv = (MapView) findViewById(R.id.map_view);
		GeoPoint gpSolo = new GeoPoint((int) (-7.56229 * 1E6), (int) (110.816517 * 1E6));
		GeoPoint gpJogja = new GeoPoint((int) (-7.824269 * 1E6), (int) (110.364532 * 1E6));
		Route route = directions(gpSolo,gpJogja);
		RouteOverlay routeOverlay = new RouteOverlay(route, Color.BLUE);
		mv.getOverlays().add(routeOverlay);
		mv.getController().animateTo(gpSolo);
		mv.getController().setZoom(15);
	}
 
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.activity_main, menu);
		return true;
	}
 
	@Override
	protected boolean isRouteDisplayed() {
		// TODO Auto-generated method stub
		return false;
	}
 
	private Route directions(final GeoPoint start, final GeoPoint dest) {
		Parser parser;
		final StringBuffer sBuf = new StringBuffer(
				"http://maps.googleapis.com/maps/api/directions/json?");
		sBuf.append("origin=");
		sBuf.append(start.getLatitudeE6() / 1E6);
		sBuf.append(',');
		sBuf.append(start.getLongitudeE6() / 1E6);
		sBuf.append("&destination=");
		sBuf.append(dest.getLatitudeE6() / 1E6);
		sBuf.append(',');
		sBuf.append(dest.getLongitudeE6() / 1E6);
		sBuf.append("&sensor=true&mode=driving");
		parser = new GoogleParser(sBuf.toString());
		Route r = parser.parse();
		return r;
	}
 
}

8. Terakhir, tambahkan uses-library com.google.android.maps dan uses-permision android.permission.INTERNET ke dalam AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.map.direction"
    android:versionCode="1"
    android:versionName="1.0" >
 
    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="15" />
    <uses-permission android:name="android.permission.INTERNET"/>    <uses-permission android:name="android.permission.READ_LOGS"/>
 
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/title_activity_main" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <uses-library android:name="com.google.android.maps"/>    </application>
 
</manifest>

Selesai. Sekarang Anda bisa menjajal project ini pada emulator. Semoga bermanfaat.

Thank you Mr. Hesham Saeed for share on stackoverflow .

NEW RELEASE! Buku best practice Pemrograman Android

24 JAM!! Pintar Pemrograman Android

detil dapat dilihat di klik link halaman ini

5 Responses to Tutorial Android Maps Google Direction menggunakan JSON

  1. newbie says:

    gan, code yg ini kan udah di tentukan k 2 koordinatx
    gmna kalo salah satux aja yag kita tntukan yg satux lg
    dari GPS???

  2. gunawan haruna says:

    Om ayib yang baik…saya sudah mencoba codenya….tapi setelah saya run..ternyata Force Close Om…. kesalahan saya di mana yagh..? bisa kirimkan source code lengkapnya nggak mas ke email saya…? gunawanharuna08ti@gmail.com

  3. gunawan haruna says:

    om ayib..saya telah berhasil menjalankan tutorialnya..nah pertanyaan saya selanjutnya…bagaimana jika titik koordinatnya tidak ditentukan langsung pada source codenya..tapi diambil dari GPS kita (sebagai posisi kita berada sekarang) dan titik yang satunya kita ambil dari database MySQL..? mohon pencerahannya OM..Terima Kasih sebelumnya..

  4. bingung npa eror trus nyobain udah brhasil ehh not responding :(

  5. BJuser says:

    Mantaaap gan, ane izin coba yaa

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>