Menampilkan Rute Tercepat (Driving Direction) Antara Dua Koordinat pada Android Maps V2

Selamat sore semuanya, pada kesempatan kali ini saya akan membahas tentang bagaimana cara menampilkan rute atau direction antara dua buah koordinat pada Android Maps API V2. Sebenarnya banyak tutorial lainnya yang membahas tentang ini, namun kebanyakan tutorial tersebut menampilkan rute dengan cara menampilkan rute-nya pada aplikasi native Google Maps. Berbeda dengan tutorial ini, tutorial ini akan benar-benar menampilkan rute pada aplikasi Android Maps yang kalian buat. 🙂  Bagaimana caranya? Yuk kita lihat.

Android Maps V2 Draw Direction

Pertama-tama, pastikan kalian telah bisa menampilkan peta pada Android, ikuti tutorial Android Maps V2 di sini. Setelah itu sediakan dua buah koordinat latitude dan longitude, jika saya koordinat pertama adalah lokasi saya berada (misalnya -6.248000,106.8322), dan koordinat kedua adalah lokasi Monas (-6.1755, 106.8273).

Setelah itu, saya menemukan sebuah kelas semacam library yang siap pakai, untuk menampilkan rute tercepat di antara dua buah titik / koordinat pada Android Maps V2. Karena open source, maka saya ganti nama kelasnya menjadi MapDirection. 😀 Inilah isi dari class MapDirection.java.

package id.web.twoh.www.mapsv2;

import java.io.InputStream;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.google.android.gms.maps.model.LatLng;
import android.annotation.SuppressLint;
import android.util.Log;

@SuppressLint("NewApi")
public class MapDirection {
    public final static String MODE_DRIVING = "driving";
    public final static String MODE_WALKING = "walking";

    public MapDirection() { }

    public Document getDocument(LatLng start, LatLng end, String mode) {
        String url = "http://maps.googleapis.com/maps/api/directions/xml?" 
                + "origin=" + start.latitude + "," + start.longitude  
                + "&destination=" + end.latitude + "," + end.longitude 
                + "&sensor=false&units=metric&mode=driving";

        try {
            HttpClient httpClient = new DefaultHttpClient();
            HttpContext localContext = new BasicHttpContext();
            HttpPost httpPost = new HttpPost(url);
            HttpResponse response = httpClient.execute(httpPost, localContext);
            InputStream in = response.getEntity().getContent();
            DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            Document doc = builder.parse(in);
            return doc;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public String getDurationText (Document doc) {
        NodeList nl1 = doc.getElementsByTagName("duration");
        Node node1 = nl1.item(nl1.getLength() - 1);
        NodeList nl2 = node1.getChildNodes();
        Node node2 = nl2.item(getNodeIndex(nl2, "text"));
        Log.i("DurationText", node2.getTextContent());
        return node2.getTextContent();
    }

    public int getDurationValue (Document doc) {
        NodeList nl1 = doc.getElementsByTagName("duration");
        Node node1 = nl1.item(nl1.getLength() - 1);
        NodeList nl2 = node1.getChildNodes();
        Node node2 = nl2.item(getNodeIndex(nl2, "value"));
        Log.i("DurationValue", node2.getTextContent());
        return Integer.parseInt(node2.getTextContent());
    }

    public String getDistanceText (Document doc) {
        NodeList nl1 = doc.getElementsByTagName("distance");
        Node node1 = nl1.item(nl1.getLength() - 1);
        NodeList nl2 = node1.getChildNodes();
        Node node2 = nl2.item(getNodeIndex(nl2, "text"));
        Log.i("DistanceText", node2.getTextContent());
        return node2.getTextContent();
    }

    public int getDistanceValue (Document doc) {
        NodeList nl1 = doc.getElementsByTagName("distance");
        Node node1 = nl1.item(nl1.getLength() - 1);
        NodeList nl2 = node1.getChildNodes();
        Node node2 = nl2.item(getNodeIndex(nl2, "value"));
        Log.i("DistanceValue", node2.getTextContent());
        return Integer.parseInt(node2.getTextContent());
    }

    public String getStartAddress (Document doc) {
        NodeList nl1 = doc.getElementsByTagName("start_address");
        Node node1 = nl1.item(0);
        Log.i("StartAddress", node1.getTextContent());
        return node1.getTextContent();
    }

    public String getEndAddress (Document doc) {
        NodeList nl1 = doc.getElementsByTagName("end_address");
        Node node1 = nl1.item(0);
        Log.i("StartAddress", node1.getTextContent());
        return node1.getTextContent();
    }

    public String getCopyRights (Document doc) {
        NodeList nl1 = doc.getElementsByTagName("copyrights");
        Node node1 = nl1.item(0);
        Log.i("CopyRights", node1.getTextContent());
        return node1.getTextContent();
    }

    public ArrayList<LatLng> getDirection (Document doc) {
        NodeList nl1, nl2, nl3;
        ArrayList<LatLng> listGeopoints = new ArrayList<LatLng>();
        nl1 = doc.getElementsByTagName("step");
        if (nl1.getLength() > 0) {
            for (int i = 0; i < nl1.getLength(); i++) {
                Node node1 = nl1.item(i);
                nl2 = node1.getChildNodes();

                Node locationNode = nl2.item(getNodeIndex(nl2, "start_location"));
                nl3 = locationNode.getChildNodes();
                Node latNode = nl3.item(getNodeIndex(nl3, "lat"));
                double lat = Double.parseDouble(latNode.getTextContent());
                Node lngNode = nl3.item(getNodeIndex(nl3, "lng"));
                double lng = Double.parseDouble(lngNode.getTextContent());
                listGeopoints.add(new LatLng(lat, lng));

                locationNode = nl2.item(getNodeIndex(nl2, "polyline"));
                nl3 = locationNode.getChildNodes();
                latNode = nl3.item(getNodeIndex(nl3, "points"));
                ArrayList<LatLng> arr = decodePoly(latNode.getTextContent());
                for(int j = 0 ; j < arr.size() ; j++) {
                    listGeopoints.add(new LatLng(arr.get(j).latitude, arr.get(j).longitude));
                }

                locationNode = nl2.item(getNodeIndex(nl2, "end_location"));
                nl3 = locationNode.getChildNodes();
                latNode = nl3.item(getNodeIndex(nl3, "lat"));
                lat = Double.parseDouble(latNode.getTextContent());
                lngNode = nl3.item(getNodeIndex(nl3, "lng"));
                lng = Double.parseDouble(lngNode.getTextContent());
                listGeopoints.add(new LatLng(lat, lng));
            }
        }

        return listGeopoints;
    }

    private int getNodeIndex(NodeList nl, String nodename) {
        for(int i = 0 ; i < nl.getLength() ; i++) {
            if(nl.item(i).getNodeName().equals(nodename))
                return i;
        }
        return -1;
    }

    private ArrayList<LatLng> decodePoly(String encoded) {
        ArrayList<LatLng> poly = new ArrayList<LatLng>();
        int index = 0, len = encoded.length();
        int lat = 0, lng = 0;
        while (index < len) {
            int b, shift = 0, result = 0;
            do {
                b = encoded.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 = encoded.charAt(index++) - 63;
                result |= (b & 0x1f) << shift;
                shift += 5;
            } while (b >= 0x20);
            int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
            lng += dlng;

            LatLng position = new LatLng((double) lat / 1E5, (double) lng / 1E5);
            poly.add(position);
        }
        return poly;
    }
}

Pada dasarnya, kelas tersebut akan menerima inputan berupa dua buah koordinat, titik awal dan titik akhir. Untuk kemudian di decode menggunakan Google Maps APIs, yang menghasilkan sebuah file XML. Nah, selanjutnya XML tersebut akan diubah menjadi sebuah ArrayList berisi LatLng (titik koordinat latitude dan longitude). Nantinya array dari latitude dan longitude itulah yang akan digunakan untuk menampilkan rute pada Android Maps V2.

Untuk menggunakan kelas tersebut, cukup copy source code di atas ke file MapDirection.java dan masukkan ke dalam project kalian. Kemudian berikut ini adalah cara memanggil kelas MapDirection tersebut :

 	//... 
 	// sediakan dua buah koordinat 
 	
 	LatLng TENDEAN = new LatLng(-6.248000,106.8322); 
 	LatLng MONAS = new LatLng(-6.1755, 106.8273);  

 	// inisialisasi kelas 

 	MapDirection MapDirection md = new MapDirection(); 			
 	LatLng source = TENDEAN; 			

        //download document XML
 	Document doc = md.getDocument(source, MONAS, MapDirection.MODE_DRIVING); 
        // menggunakan mode driving  

 	// method untuk mendapatkan point direction / rute 			
 	ArrayList<LatLng> directionPoint = md.getDirection(doc);  

 	// konfigurasi rute, warna garis, ketebalan, dan sebagainya 			
 	PolylineOptions rectLine = new PolylineOptions().width(5).color(Color.RED);  

 	// looping pada array koordinat direction point, dan menambahkannya ke PolyLineOptions 			

 	for (int i = 0; i &lt; directionPoint.size(); i++) 
 	{ 				
 		rectLine.add(directionPoint.get(i)); 			
 	}  
 
 	// menampilkan rute di peta yang kita buat 			
 	googleMap.addPolyline(rectLine);  

 	//.... 

Begitulah caranya, pada kode di atas pertama-tama kita akan meminta Document XML-nya terlebih dahulu dengan memanggil fungsi getDocument(source,destination). Setelah kita mendapatkan document xml tersebut, baru kita parsing menjadi array koordinat lat long menggunakan fungsi getDirection(doc).

Setelah kita mendapatkan array koordinat, (ingat, garis adalah kupulan dari titik, jadi untuk bisa menampilkan sebuah rute yang berupa garis, kita perlu banyak titik-titik), kita akan menambahkan koordinat itu satu persatu ke dalam PolyLineOptions. PolyLineOptions adalah suatu kelas yang selain berfungsi untuk menampung array of koordinat tersebut, juga bisa berfungsi untuk mengatur warna garis rute, ketebalan, dan sebagainya. Selanjutnya, kita akan menampilkan rute tersebut pada Android Maps dalam bentuk PolyLine.

Dan, inilah hasilnya :

route_androidmapsv2

Menampilkan rute pada Android Maps V2

route_androidmapsv2_bv

Menampilkan rute pada Android Maps V2

Berhasil kan. 🙂 Sekian, semoga membantu.

NOTE : kode untuk pemanggila kelas MapDirection di atas hanyalah sebagai hint/petunjuk. Jangan kalian copy mentah-mentah. Saya sarankan menerapkannya pada sebuah AsyncTask Class yang akan mendownload file XML tersebut pada background. Jika kalian langsung menerapkan tanpa AsyncTask atau di main class, maka akan terjadi NetworkOnMainThreadException, yang akan menyebabkan aplikasi force close.



Download aplikasi kami di Google Play Store


23 Comments

  1. christiawan October 20, 2013
  2. agungs May 8, 2014
  3. agungs May 8, 2014
    • Hafizh Herdi Naufal May 12, 2014
  4. chandra May 16, 2014
  5. narwa June 24, 2014
  6. Galuh July 1, 2014
  7. Ganjar July 4, 2014
    • Hafizh Herdi July 31, 2015
  8. uki September 13, 2014
  9. arif October 31, 2014
  10. marshel July 30, 2015
    • Hafizh Herdi July 30, 2015
  11. Dary July 31, 2015
    • Hafizh Herdi July 31, 2015
  12. Haries September 3, 2015
    • Hafizh Herdi September 3, 2015
  13. Irfan September 22, 2015
  14. Nila July 23, 2016
    • Hafizh Herdi August 10, 2016
      • eko prayitno August 21, 2016
  15. muhel July 23, 2016
  16. muhel July 23, 2016

Leave a Reply