Android’de Directions API ile Rota Çizme

Günümüzde konum bilgisi kullanarak hayatımızı birçok alanda kolaylaştırması sağlayan yazılımlar bulunmaktadır. Mobil uygulamalarda GPS, araba kullanırken ya da yaya olarak yürürken, ulaşmak istediğimiz noktaya gidebilmek için yol tarifi yapması, bulunduğunuz konum çevresinde en yakın eczaneye ulaşmak gibi birçok konuda hayatımızı kolaylaştırmaktadır.

Bu makalemde, bir Android uygulamasında Google Directions API ‘yi kullanarak haritada belirlenen iki nokta arasında nasıl bir rota çizileceğini ve bu rotaya ne kadar sürede varılacağını göstereceğim.

Örnek projemizi kodlamaya başlamadan önce bazı işlemler yapmamız gerekmektedir.Bu işlemleri sırayla yapmaya başlayalım.

1- Google Play Services Yükleme

Google haritayla ilgili bir geliştirme yapacağımızdan dolayı, Google Play Services yüklememiz gerekmektedir. Bunun için Tools->Sdk manager’ı açıp Sdk Tools bölümünden Google Play Services işaretleyip, yükleme işlemini gerçekleştirin.

2- Google Maps API Key Oluşturma

3-Gerekli Kütüphanelerin Eklenmesi

Android Studio Ide ile oluşturduğum projemin app dizinin altındaki build.gradle dosyasını açıyoruz. Dependencies kod bloklarının arasına aşağıdaki kodları yerleştirerek Google Play services kütüphanesini yüklüyoruz.

implementation 'com.google.android.gms:play-services-maps:17.0.0'

4-AndroidManifest Dosyasına İlgili Ayarları Ekleme

Kullanıcının konumu belirlemek için izin tanımlamamız gerekir. Aşağıdaki izin kodunu da AndroidManifest.xml dosyasında application tag’nin üst kısmına yerleştirin.

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

AndroidManifest dosyasına, daha önce üretmiş olduğumuz Google API Key’i ekleme işlemini yapacağız. Application tag arasına aşağıda görmüş olduğunuz meta-data tag kodunun içindeki value özelliğine Google API Key’i ekleyeniz.

<meta-data android:name="com.google.android.geo.API_KEY"
   android:value="AIzaSyBconZdqpSflHNcs6t-btfk0Rlo1Lex7wo" />

5-Xml Kodları

Haritayı gösterebilmek için SupportMapFragment sınıfını fragment ile kullanıyoruz.

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:map="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/map"
    android:name="com.google.android.gms.maps.SupportMapFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

4-Java Kodları

İlgili rotayı çizebilmek için ilk önce Google Map Directions web servisine API Key, başlangıç ve varış noktalarının konum bilgilerini bir url ile göndermeniz gerekir. İlgili url ile web servise bağlandığınızda, rotayı ne kadar sürede bitirebileceğiniz, rotanın kaç km olduğu, yol tarifleri hakkında detaylı bilgiler json verisi halinde gelecektir. Bu kısmı ve rotanın harita çizilmesi MainActivity sınıfında yapılmıştır. Detaylı anlatım kodlarda bulunmaktadır.

import androidx.fragment.app.FragmentActivity;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.*;
import android.preference.PreferenceManager;
import android.widget.Toast;
import com.google.android.gms.maps.*;
import com.google.android.gms.maps.model.*;
import org.json.JSONObject;
import java.io.*;
import java.net.*;
import java.util.*;

public class MainActivity extends FragmentActivity implements OnMapReadyCallback {

    private GoogleMap mMap;
    private LatLng mOrigin;
    private LatLng mDestination;
    private Polyline mPolyline;
    ArrayList<LatLng> mMarkerPoints;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // SupportMapFragment ile haritayı yükleyeceğimiz arayüz elemanını tanımlıyoruz
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map);

        mapFragment.getMapAsync(this);

        mMarkerPoints = new ArrayList<>();
    }
    //Harita üzerinde yolun başlangıç ve bitiş noktasını imleçler ile işaretleyerek seçme
    @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;
        mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
            @Override
            public void onMapClick(LatLng point) {
                // Her lokasyon yolunu çizme işleminden sonra yeni yol çizimi için harita refresh yapılıyor
                if(mMarkerPoints.size()>1){
                    mMarkerPoints.clear();
                    mMap.clear();
                }
                mMarkerPoints.add(point);

                //İmleçleri oluşturan sınıfı tanımladık
                MarkerOptions options = new MarkerOptions();
                //İmleci, haritada belirtilen noktalara eklenmesi için ilgili yerin değerini atadık
                options.position(point);
                //DirectionsJSONParser sınıfında, yol süresi değerini SharedPreferences ile taşıyıp
                // imleçde gösterdik
                SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(MainActivity.this);
                options.title("Duration: " +preferences.getString("duration", null));

                /**
                 * İmleçlerin görsellerini belirleme, Başlangıç imlecini yeşil
                 * lokasyonu bitişini belirten imleç ise kırmızı olarak belirledim
                 */
                if(mMarkerPoints.size()==1){
                    options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN));
                }else if(mMarkerPoints.size()==2){
                    options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED));
                }

                // Haritada marker(imleç) ekleniyor
                mMap.addMarker(options);

                // Google Directions web servis urlsini hazırlayan ve web servisi kullanan metodu çağırdık
                if(mMarkerPoints.size() >= 2){
                    mOrigin = mMarkerPoints.get(0);
                    mDestination = mMarkerPoints.get(1);
                    drawRoute();
                }

            }
        });
    }
    // Google Directions API den konum datalarını kullanabilmek için web servis ile
    //bağlantı kuracağımız url hazırlayan metodu çağırdık ve web servisi çalıştırdık
    private void drawRoute(){
        String url = getDirectionsUrl(mOrigin, mDestination);

        DownloadTask downloadTask = new DownloadTask();
        downloadTask.execute(url);
    }

    //Haritada belirttiğiniz başlangeç ve bitiş imleçlerinin koordinatlarını API Key ile kullanarak
    //çizilecek düzergah ile ilgili bilgileri elde etmek adına url olusturan metod
    private String getDirectionsUrl(LatLng origin,LatLng dest){

        String str_origin = "origin="+origin.latitude+","+origin.longitude;
        String str_dest = "destination="+dest.latitude+","+dest.longitude;

        // API Key parametre olarak hazırlama
        String key = "key=" +"AIzaSyBconZdqpSflHNcs6t-btfk0Rlo1Lex7wo";

        String parameters = str_origin+"&"+str_dest+"&"+key;
        String output = "json";

        // Oluşturduğumuz parametreleri kullanarak url yi oluşturuyoruz
        String url = "https://maps.googleapis.com/maps/api/directions/"+output+"?"+parameters;
        return url;
    }

    private String downloadUrl(String strUrl) throws IOException {
        String data = "";
        InputStream iStream = null;
        HttpURLConnection urlConnection = null;
        try{
            // Hazırladığımız url yi kullanarak web servise Http bağlantısı ile sağlıyoruz
            URL url = new URL(strUrl);
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.connect();

            // webservisden gelen json datayı okuyup, data değişkenine atadık
            iStream = urlConnection.getInputStream();

            BufferedReader br = new BufferedReader(new InputStreamReader(iStream));
            StringBuffer sb  = new StringBuffer();
            String line = "";
            while( ( line = br.readLine())  != null){
                sb.append(line);
            }
            //json veriyi data değişkenine atadıkve metodda return yaptık
            data = sb.toString();
            br.close();

        }catch(Exception e){
            //Log.d("Exception on download", e.toString());
        }finally{
            iStream.close();
            urlConnection.disconnect();
        }
        return data;
    }

    /** Bu sınıf da, Google Directions URL kullanarak, rotanın kaç km. olduğu, ne kadar sürede gidilebildiği
     * gibi bilgileri barındıran json datayı çektik */
    private class DownloadTask extends AsyncTask<String, Void, String> {
        @Override
        protected String doInBackground(String... url) {
            String data = "";
            try{
                data = downloadUrl(url[0]);

            }catch(Exception e){
                //Log.d("Background Task",e.toString());
            }
            return data;
        }

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            //Google Directions bilgisini, JSON formatını parse ederek almayı sağlayan sınıf
            ParserTask parserTask = new ParserTask();
            parserTask.execute(result);
        }
    }

    /** Bu sınıf Google Directions bilgisini, JSON formatını parse ederek almayı sağlar  */
    private class ParserTask extends AsyncTask<String, Integer, List<List<HashMap<String,String>>> >{
        @Override
        protected List<List<HashMap<String, String>>> doInBackground(String... jsonData) {
            JSONObject jObject;
            List<List<HashMap<String, String>>> routes = null;

            try{
                jObject = new JSONObject(jsonData[0]);
                //DirectionsJSONParser sınıfında tüm json çözümlenir.
                DirectionsJSONParser parser = new DirectionsJSONParser();
                routes = parser.parse(jObject,MainActivity.this);
            }catch(Exception e){
                e.printStackTrace();
            }
            return routes;
        }

        // Json çözümlendikten sonra, harita üzerinde rotayı(path) çizmeyi sağlayan metod
        @Override
        protected void onPostExecute(List<List<HashMap<String, String>>> result) {
            ArrayList<LatLng> points = null;
            PolylineOptions lineOptions = null;

            for(int i=0;i<result.size();i++){
                points = new ArrayList<LatLng>();
                lineOptions = new PolylineOptions();

                List<HashMap<String, String>> path = result.get(i);

                for(int j=0;j<path.size();j++){
                    HashMap<String,String> point = path.get(j);

                    double lat = Double.parseDouble(point.get("lat"));
                    double lng = Double.parseDouble(point.get("lng"));
                    LatLng position = new LatLng(lat, lng);
                    points.add(position);
                }

                //PolylineOptions ile rota üzerinde noktalar ekleyerek, çizginin rengini ve genişliğini belirleme
                lineOptions.addAll(points);
                lineOptions.width(8);
                lineOptions.color(Color.RED);
            }

            if(lineOptions != null) {
                if(mPolyline != null){
                    mPolyline.remove();
                }
                mPolyline = mMap.addPolyline(lineOptions);

            }else
                Toast.makeText(getApplicationContext(),"Rota bulanamadı", Toast.LENGTH_LONG).show();
        }
    }

}

DirectionsJSONParser sınıfında ise web servisden gelen Json veriyi çözümleyip, içindeki bilgileri ArrayList yapısına ekleyerek MainActivity sınıfında kullanılması sağlanmıştır. Ek olarak DirectionsJSONParser sınıfında Json veriden gelen polyline değerini (rota yolunun şifrelenmiş çizgileri) çözümleyen bir metod yazılmıştır. Bu metod sayesinde  rota yolunun çizilebilmesi için gerekli enlem, boylam değerleri elde edilir. Detaylı anlatım kodlarda bulunmaktadır.

import android.content.*;
import android.preference.PreferenceManager;
import com.google.android.gms.maps.model.LatLng;
import org.json.*;
import java.util.*;
public class DirectionsJSONParser {
    /** Google Directions URL kullanarak web servisden elde edilen JSONObject çözümlenerek,
     rotayı ne kadar sürede bitirebileceğiniz, rotanın kaç km olduğu, yol tarifleri hakkında detaylı bilgiler elde edilir   */
    public List<List<HashMap<String,String>>> parse(JSONObject jObject, Context context){

        List<List<HashMap<String, String>>> routes = new ArrayList<>() ;
        JSONArray jRoutes = null;
        JSONArray jLegs = null;
        JSONArray jSteps = null;

        try {
            jRoutes = jObject.getJSONArray("routes");

            for(int i=0;i<jRoutes.length();i++){
                jLegs = ( (JSONObject)jRoutes.get(i)).getJSONArray("legs");

                JSONObject c = jLegs.getJSONObject(i);
                JSONObject vo = c.getJSONObject("duration");
                //Rotaya varış süresini, SharedPreferences nesnesine atadım. Haritada gösterimi, MainActivity sınıfında.
                SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
                SharedPreferences.Editor editor = prefs.edit();
                editor.putString("duration", vo.getString("text"));
                editor.commit();

                List path = new ArrayList<HashMap<String, String>>();
                for(int j=0;j<jLegs.length();j++){
                    jSteps = ( (JSONObject)jLegs.get(j)).getJSONArray("steps");
                    for(int k=0;k<jSteps.length();k++){
                     //Polyline çözümleyerek, rota noktalarının enlem, boylam bilgisi alma
                        String polyline = "";
                        polyline = (String)((JSONObject)((JSONObject)jSteps.get(k)).get("polyline")).get("points");
                        List<LatLng> list = decodePoly(polyline);

                        for(int l=0;l<list.size();l++){
                            HashMap<String, String> hm = new HashMap<String, String>();
                            hm.put("lat", Double.toString(((LatLng)list.get(l)).latitude) );
                            hm.put("lng", Double.toString(((LatLng)list.get(l)).longitude) );
                            path.add(hm);
                        }
                    }
                    routes.add(path);
                }
            }

        } catch (JSONException e) {
            e.printStackTrace();
        }catch (Exception e){
        }
        return routes;
    }

    /**
     * Polyline (rota yolunun şifrelenmiş çizgileri) çözümleyerek, rota noktalarının enlem, boylam bilgisini döner
     */
    private List<LatLng> decodePoly(String encoded) {

        List<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 p = new LatLng((((double) lat / 1E5)),
                    (((double) lng / 1E5)));
            poly.add(p);
        }
        return poly;
    }
}

Örneklediğim projemin kodlarını indirmek isterseniz; yapmanız gereken tek şey aşağıya koyduğum KODLARI İNDİR resmine tıklamak.

Tavsiye Edilen Yazılar

Henüz yorum yapılmamış, sesinizi aşağıya ekleyin!


Bir Yorum Ekle

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir