Günümüzde mobil uygulamalarda en çok kullanılan servislerden biri konum servisleridir. Mobil/seyyar olmanın getirileri konum servisleriyla alınabilir. Android işletim sistemi de uygulamalar için kullanıcının konumunu paylaşan detaylı bir kütüphane sunar. Android'de mobil cihazın konumu aşağıdaki yöntemlerle bulunur:
- GPS (Global Positioning System): Eğer cihazda bir GPS modülü varsa, mobil cihaz uydulardan gelen bilgiyle kullanıcının yerini hesaplama yeteneğine sahiptir. Android işletim sistemi de uygulamadan konum talebi geldiğinde GPS’i devreye sokarak kullanıcının konumunu uygulamaya bildirir. GPS, teknolojisi gereği kapalı alanlarda çalışmamaktadır ve tam bağlantı sırasında pek pil dostu değildir. Bunlara karşın oldukça yüksek hassasiyette konum bildirdiğinden navigasyon uygulamaları GPS kullanımını talep etmektedir. Sizin uygulamanız da kullanıcının konumunu kesin bir şekilde bilmeyi gerektiriyorsa GPS verisini kullanabilirsiniz.
- NETWORK: Cihazda aktif bir GSM bağlantısı varsa (bir SIM kartı takılıysa ve şebekeye bağlıysa), Android cihazın bağlı bulunduğu baz istasyonlarından kullanıcının yeri tahmin edilebilir. Burada yapılan, baz istasyonu bilgisinin merkezi bir veri tabanına gönderilerek bu istasyonların konum bilgilerinden kullanıcının yerinin tahmin edilmesidir. Bu sistem baz istasyonu sayısının fazla olduğu bölgelerde (şehir içi alanlar) tatmin edici sonuçlar vermesine rağmen (40 metre sapma), baz istasyonu sayısının düşük olduğu kırsal alanlarda sonuçların yeterliliği düşmektedir (1-2 km sapma). Aynı zamanda bu sistem bir internet bağlantısı gerektirebilir. Baz istasyonlarının dışında WifiHotSpot’lar da aynı yöntemle kullanılmaktadır.
- PASSIVE: Aslında bir sensör olmamasına rağmen, Android işletim sistemi pasif konum bilgisi adı altında işletim sisteminin bellekte (cache) tuttuğu eski konum bilgilerinden yola çıkarak kullanıcının konumuyla ilgili bilgi verebilir. Burada elde edilen veri zaman zaman doğru sonuçlar verse de genellikle tahmini ve eski konumlar verecektir. Eğer uygulamanızda kullanıcının anlık konumuna ihtiyaç duyuyorsanız bu yöntemden kaçınmalısınız.
Bir uygulamanın konum bilgisi servislerinden yararlanması için AndroidManifest.xml dosyasında bazı izinler alması gerekir. Hassasiyet sırasına göre izinler şöyledir:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
Burada ACCESS_FINE_LOCATION değeri GPS gibi servislerden kesin konum bilgisi almanıza yarar. ACCESS_COARSE_LOCATION ise GSM ya da WiFi kaynaklı konum bilgisi almanıza yarar. İlçe ve şehir bilgisi bu seviyede bir izinle alınabilir.
Cihazdan konum bilgilerinin nasıl elde edileceğine kabataslak bir örnekle bakalım. Bunun için bir kendimiz bir LocationManager yazmalıyız. Çünkü bazı kriterlerimiz var. Ayrıca konum bilgilerini anlık olarak almak için bir LocationListener ile işe koyulalım:
//Dosya Adı: CustomLocationManager.java
import java.util.List;
import android.content.Context;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
public class CustomLocationManager {
private static final long UZAKLIK_DEGISIMI = 20;
private static final long SURE = 1000 * 30;
private Location mMevcutKonum;
private LocationManager mLocationManager;
private KonumListener mKonumListener;
private static CustomLocationManager INSTANCE;
private CustomLocationManager(Context context){
mLocationManager = (LocationManager)
context.getSystemService(Context.LOCATION_SERVICE);
mKonumListener = new KonumListener();
}
public static CustomLocationManager getInstance(Context context){
if(INSTANCE == null) {
INSTANCE = new CustomLocationManager(context);
}
return INSTANCE;
}
public void baslaKonumGuncellemesi(){
Criteria kriter = new Criteria();
kriter.setAccuracy(Criteria.ACCURACY_COARSE);
kriter.setAltitudeRequired(false);
kriter.setSpeedRequired(false);
kriter.setPowerRequirement(Criteria.POWER_MEDIUM);
kriter.setCostAllowed(false);
String bilgiSaglayici =
mLocationManager.getBestProvider(kriter, true);
if (bilgiSaglayici == null){
List<String> bilgiSaglayicilar =
mLocationManager.getAllProviders();
for (String tempSaglayici : bilgiSaglayicilar){
if (mLocationManager.isProviderEnabled(tempSaglayici))
bilgiSaglayici = tempSaglayici;
}
}
//kriterlere uyan bir LocationManager al
mLocationManager.requestLocationUpdates(
bilgiSaglayici,
SURE,
UZAKLIK_DEGISIMI,
mKonumListener);
}
public void durdurKonumGuncellemesi(){
if (mLocationManager != null)
mLocationManager.removeUpdates(mKonumListener);
}
public Location getMevcutKonum() {
return mMevcutKonum;
}
//Inner class - Dahili sınıf
private class KonumListener implements LocationListener{
public void onLocationChanged(Location location) {
mMevcutKonum = location;
}
public void onStatusChanged(String provider,
int status, Bundle extras){}
public void onProviderDisabled(String provider){}
public void onProviderEnabled(String provider) {}
}
}
Yukarıda sadece bir kere oluşturulabilmesi için getInstance() metodu eklediğimiz ve yapılandırıcı metodunu private yaptığımız CustomLocationManager sınıfı üzerinden Android'in konum bilgisi sağlayıcılarını dinleyebiliriz. Bu kodu incelediğimizde iki önemli konum sınıfı görürüz:
- CustomLocationManager: İşletim sisteminin konum servislerine erişimi bu sınıf üzerinden sağlanır. Burada yapılması gereken yapılandırıcı metoda bir Context sağlamaktır. Bu Context bilgisiyle konum servislerine erişebileceğiz. Ardından hangi konum bulucu sensörü kullanacağımızı seçerek konum güncellemelerine başlamamız gerekir.
- KonumListener: Kendi yarattığımız bir sınıf olan KonumListener, Android’in LocationListener arayüzündeki metodları kullanır. Burada bize sunulan dört metot vardır;
- onLocationChanged: Bir konum güncellemesi geldiğinde (örn. cihazın hareketi sonucu güncellenebilir) bu metot uyarılır ve güncel konum location parametresiyle mMevcutKonum değişkenine atılır.
- onStatusChanged: Konum bilgisi veren servisin durumu değiştiğinde bu metot uyarılır. Eğer konum alınamıyorsa (örn. GPS sinyali kaybolduysa) bu metot çağırılarak ilgili servisin (provider) durumu status değişkeniyle bildirilir. Buradaki değerler OUT_OF_SERVICE (hizmet dışı), TEMPORARILY_UNAVAILABLE (geçici olarak hizmet dışı) ve AVAILABLE (çalışıyor) şekildedir. Bu değerler LocationManager içinde statik olarak saklanır.
- onProviderEnabled: İlgili konum servisi kullanıcı tarafından etkinleştirilirse çalışır (örn. kullanıcının elle GPS’i açması).
- onProviderDisabled: İlgili konum servisinin kullanıcı tarafından kapatıldığını belirtir.
KonumListener sınıfı CustomLocationManager sınıfının içinde kullanılmıştır. İkisi birlikte çalışarak işletim sisteminden gelen konum güncellemelerini uygulamaya bildirir. Şimdi kodumuzda bunun nasıl gerçekleştiğine bakalım. CustomLocationManager sınıfının yapılandırıcı metoduna bakalım:
private CustomLocationManager(Context context){
mLocationManager = (LocationManager)
context.getSystemService(Context.LOCATION_SERVICE);
mKonumListener = new KonumListener();
}
Burada Context içerisinden LOCATION_SERVICE seçeneğiyle konum servislerine erişim isteğini gerçekleştiriyoruz. Bize dönen nesne LocationManager sınıfından olduğu için cast edip locationManager değişkenine atıyoruz. Aynı zamanda burada mKonumListener değişkenine yeni bir KonumListener nesnesi tanımlıyoruz. Bu işlemden sonra getInstance() metoduyla oluşturduğumuz CustomLocationManager’a erişebiliriz.
public static CustomLocationManager getInstance(Context context){
if(INSTANCE == null) {
INSTANCE = new CustomLocationManager(context);
}
return INSTANCE;
}
Bu şekilde CustomLocationManager nesnesinden sadece bir adet var olmasını sağlıyoruz. Uygulama içerisinden erişmek istediğimizde aşağıdaki kod yeterlidir:
CustomLocationManager.getInstance(getApplicationContext());
Şimdi de konum güncellemelerini yönettiğimiz metotlara bakalım:
public void baslaKonumGuncellemesi(){
Criteria kriter = new Criteria();
kriter.setAccuracy(Criteria.ACCURACY_COARSE);
kriter.setAltitudeRequired(false);
kriter.setSpeedRequired(false);
kriter.setPowerRequirement(Criteria.POWER_MEDIUM);
kriter.setCostAllowed(false);
String bilgiSaglayici = mLocationManager.getBestProvider(kriter, true);
if (bilgiSaglayici == null){
List<String> bilgiSaglayicilar = mLocationManager.getAllProviders();
for (String tempSaglayici : bilgiSaglayicilar){
if (mLocationManager.isProviderEnabled(tempSaglayici))
bilgiSaglayici = tempSaglayici;
}
}
mLocationManager.requestLocationUpdates(
bilgiSaglayici,
SURE,
UZAKLIK_DEGISIMI,
mKonumListener);
}
Android işletim sistemi belirli kriterlere göre uygun konum servisinin seçilmesi için Criteria sınıfını sunar. Bununla uygulama için uygun konum servisini bulabiliriz. Burada kullanabileceğimiz seçenekler;
- Accuracy: Konumun hassasiyetini belirtir. FINE seçeneği GPS gibi kesin sonuçlar veren servisler için yapılır. COARSE ise şebeke üzerinde ya da pasif çalışan konum servislerinin çağrılmasında kullanılır.
- AltitudeRequired: Konumla birlikte yüksekliğe de ihtiyacımız varsa bunu belirtebiliriz.
- SpeedRequired: Eğer bir navigasyon uygulaması yapıyorsak ve kullanıcının hızına ihtiyacımız varsa bunu ekleyebiliriz.
- PowerRequirement : Güç ihtiyacını bu değişkenle kontrol edebiliriz. Eğer uygulama arka planda çalışırken konum bekliyorsa cihazın pil tüketimini göze almamız gerekir. GPS servisi yoğun biçimde pil harcayan bir servistir.
- CostAllowed : Konum servisi kullanıcıya bir ücret yansıtacaksa (örn. internet bağlantısı) buradan seçilebilir.
Burada ihtiyacımız olan servisle ilgili kriterleri girdikten sonra getBestProvider metoduyla işletim sisteminin bize bir servis ismi vermesini sağlıyoruz.
String bilgiSaglayici = mLocationManager.getBestProvider(kriter, true);
Bu noktadan sonra requestLocationUpdates fonksiyonuyla cihazdan gelen konum güncellemelerini takip edebiliriz. Burada SURE değişkeni iki konum güncellemesi arasında geçen zamanı, UZAKLIK_DEGISIMI ise konum güncellemesinin gerçekleşeceği gerçek konum değişimini belirtir. Bizim uygulamamız 30 saniyede bir güncelleme yaparken 20 metrelik bir değişim olduğunda güncelleme talep ediyor. Bu noktadan sonra CustomLocationManager konum dinlemelerini takip ederek onLocationChanged metodunda bizi uyaracak ve mMevcutKonum değişkenine güncel konumu atayacaktır.
private class KonumListener implements LocationListener{
public void onLocationChanged(Location location) {
mMevcutKonum = location;
}
public void onStatusChanged(String provider, int status, Bundle extras){}
public void onProviderDisabled(String provider){}
public void onProviderEnabled(String provider) {}
}
Kod içerisinde güncel konumu da aşağıdaki metot yardımıyla elde edebiliriz:
public Location getMevcutKonum() {
return mMevcutKonum;
}
Konum dinlemesini durdurmak için durdurKonumGuncellemesi metodu çağrılır:
public void durdurKonumGuncellemesi(){
if (mLocationManager != null)
mLocationManager.removeUpdates(mKonumListener);
}
Siz de yukarıdaki CustomLocationManager sınıfına benzer sınıflar yazarak gerekli yerlerde Location sınıfı üzerinden kullanıcının konumunu öğrenebilirsiniz.