İçeriğe geç
academia.sh

Ders 03 / 14

Konum ve Haritalar

Konum sağlayıcısı konum güncellemelerini bir geri çağrıyla verir; en küçük aralık kuralı hangi güncellemenin alıcıya ulaşacağını belirler, çalışma zamanı izni geri alınınca sonraki güncellemeler gelmez. Ders bu iki kuralın teslimini ölçer.

Yayın Güncelleme

Bu derste

  • Kesin ve yaklaşık konum izinlerini ve konum sağlayıcısının geri çağrı biçimini tanır
  • En küçük aralık kuralının hangi konum güncellemelerini düşürdüğünü ölçer
  • Aralık bire inince bütün güncellemelerin birebir ulaştığını gösterir
  • İzin geri alındıktan sonra üretilen güncellemelerin kayıp olduğunu gösterir
İçindekiler

Önceki derste olay bir sunucudan aygıta geliyordu ve servis biriken iletileri daraltıyordu. Konumda olay aygıtın içinde doğar: sağlayıcı kullanıcının yerini sürekli ölçer ve her ölçümü bir konum güncellemesi olarak uygulamaya verir. Bir kurye uygulamasında bu saniyelerce süren bir akıştır ve alıcının hepsine ihtiyacı yoktur. Bu derste de aynı soruyu soruyoruz: gönderilen bu olay alıcıya kaç kopya olarak ulaştı?

// Arrival.kt — gonderilen bir olayin aliciya kac kopya olarak ulastigini siniflandirir
class Signal(val key: String, val seq: Int)

class Arrival(val label: String, val sent: Signal, received: List<Signal>) {
    val copies: Int = received.count { it.seq == sent.seq }
    val verdict: String = when {
        copies > 1 -> "yinelenen"
        copies == 1 -> "birebir"
        received.any { it.key == sent.key && it.seq > sent.seq } -> "ezilen"
        else -> "kayip"
    }

    fun line() {
        println("$label: anahtar=${sent.key} | kopya=$copies -> $verdict")
    }
}

fun countArrivals(arrivals: List<Arrival>) {
    for (name in listOf("birebir", "yinelenen", "ezilen", "kayip")) {
        println("$name: ${arrivals.count { it.verdict == name }}")
    }
}

Sınıflandırma ilk derslerdekiyle aynıdır. Kural alıcının listesinde aynı sırayı taşıyan kopyaları sayar; hiç kopya yoksa aynı anahtarla daha sonraki bir güncellemenin ulaşıp ulaşmadığına bakar. İçeriği ve nedeni görmez.

İzin ve Sağlayıcı

Konum, çalışma zamanı izni isteyen bir yetenektir. Bildirim dosyasında iki izin tanımlanır: kesin konum ve yaklaşık konum. Kullanıcı yalnız yaklaşık konumu verebilir ya da hiçbirini vermeyebilir; izin verildikten sonra ayarlardan da geri alınabilir. Uygulama bu üç durumu da ele almak zorundadır.

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

Konum sağlayıcısı güncellemeleri bir geri çağrıyla verir. Uygulama en küçük aralığı isteğe yazar ve sağlayıcı bu aralıktan sık güncelleme üretmez.

// Platform kodu: CourierTracker
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager

class CourierTracker(private val manager: LocationManager) : LocationListener {
    fun start() {
        manager.requestLocationUpdates(
            LocationManager.GPS_PROVIDER, 5000L, 10f, this
        )
    }

    override fun onLocationChanged(location: Location) {
        publish(location.latitude, location.longitude)
    }
}

Parça iki sayı verir: milisaniye cinsinden en küçük süre aralığı ve metre cinsinden en küçük uzaklık. İkisi de uygulamanın istediği değerlerdir; sağlayıcının gerçekte ne sıklıkla ürettiğini bu parça söylemez. Model, platformun bu kuralını kurar; model platformun kendisi değildir. Harita görünümü bu modelin dışındadır: çizim bir teslim sorusu değil, bir görüntüleme sorusudur ve bu derste ölçülmez.

En Küçük Aralık Kuralı

Modelde güncelleme bir Signaldır ve anahtarı kuryenin kimliğidir. Sıra numarası güncellemenin üretilme adımıdır. En küçük aralık kuralı, son kabul edilen güncellemeden bu yana yeterince adım geçmemişse güncellemeyi düşürür. Aralığın sayısı modelin uydurma değeridir; sağlayıcının gerçek aralığı değildir.

// Sampling.kt — en kucuk aralik kuralini ve iznin geri alinmasini kurar
fun sample(sent: List<Signal>, minGap: Int): List<Signal> {
    val kept = mutableListOf<Signal>()
    for (s in sent) {
        if (kept.isEmpty() || s.seq - kept.last().seq >= minGap) kept.add(s)
    }
    return kept
}

fun revoke(delivered: List<Signal>, revokedAt: Int): List<Signal> =
    delivered.filter { it.seq < revokedAt }

Sekiz güncelleme üretiyoruz, aralık üç adım.

// Main.kt — en kucuk aralik kurali arada kalan konum guncellemelerini dusurur
fun main() {
    val sent = (1..8).map { Signal("konum.kurye", it) }
    val received = sample(sent, minGap = 3)
    println("ulasan siralar: ${received.map { it.seq }}")

    val arrivals = sent.map { Arrival("olay-${it.seq}", it, received) }
    arrivals.forEach { it.line() }
    countArrivals(arrivals)
}
ulasan siralar: [1, 4, 7]
olay-1: anahtar=konum.kurye | kopya=1 -> birebir
olay-2: anahtar=konum.kurye | kopya=0 -> ezilen
olay-3: anahtar=konum.kurye | kopya=0 -> ezilen
olay-4: anahtar=konum.kurye | kopya=1 -> birebir
olay-5: anahtar=konum.kurye | kopya=0 -> ezilen
olay-6: anahtar=konum.kurye | kopya=0 -> ezilen
olay-7: anahtar=konum.kurye | kopya=1 -> birebir
olay-8: anahtar=konum.kurye | kopya=0 -> kayip
birebir: 3
yinelenen: 0
ezilen: 4
kayip: 1

Bu dersin teslimi ezilendir. 2 ve 3 numaralı güncellemeler hiç ulaşmadı, ama aynı anahtarla 4 numaralı güncelleme ulaştı ve onların yerini aldı; 5 ve 6 için 7 numaralı güncelleme aynı işi yaptı. Konum için bu istenen davranıştır: yeni konum eskisinin yerini alır. Sekizinci güncelleme ise kayıp oldu, çünkü ondan sonra aynı anahtarla hiçbir güncelleme gelmedi. Kural son güncellemenin düşmesini ezilen saymaz; son durum kullanıcıya hiç gösterilmemiştir.

SY1. Model, kuryeyi tek bir anahtarla kurar ve güncellemeleri eşit aralıklı adımlara koyar. Platformda sağlayıcı güncellemeleri düzensiz aralıkla üretir, pil tasarrufu için aralığı uzatabilir ve süre ve uzaklık eşikleri birlikte uygulanır, yani ikisi de sağlanmadan güncelleme gelmez; bunlar modelde yoktur.

Kesin ve Yaklaşık Konum

İki izin iki ayrı duyarlık düzeyidir. Kesin konum, uydu ve ağ kaynaklarını birlikte kullanarak sokak düzeyinde bir yer verir; yaklaşık konum ise yalnızca kaba bir bölge verir. Kullanıcı izin ekranında ikisinden birini seçebilir. Yalnızca yaklaşık konumu seçen kullanıcının uygulaması kesin konum isteyen bir çağrı yaptığında, platform isteği yaklaşık düzeye indirir. Çağrı hata vermez; güncellemeler gelir, yalnız duyarlıkları düşüktür.

Bu, teslim modelinin görmediği bir yerdir. Kural bir güncellemenin ulaşıp ulaşmadığını sayar; ulaşan güncellemenin ne kadar kesin olduğunu sormaz. Yaklaşık konumla gelen dört güncelleme ile kesin konumla gelen dört güncelleme kural gözünde aynı sonucu verir: birebir 4. Duyarlık, uygulamanın alıcı tarafında ayrıca denetleyeceği bir özelliktir. Kesin konuma ihtiyaç duyan bir kurye uygulaması, yaklaşık düzeyde gelen bir güncellemeyi kullanıcıya göstermeden önce izin durumuna bakmalı ve kullanıcıdan kesin konumu istemelidir.

Arka Planda Konum

Konum güncellemesi ön plandaki uygulama için bir şeydir, arka plandaki uygulama için başka. Uygulama ekrandan çıktığında platform, pil tasarrufu için güncelleme sıklığını kendisi düşürebilir ve ayrı bir arka plan konumu izni olmayan uygulamaya güncelleme hiç vermeyebilir. Bu iki durumun teslim modelindeki karşılığı farklıdır.

Sıklığın düşürülmesi, aralık kuralının büyük bir değerle çalışmasına benzer: arada kalan güncellemeler hiç üretilmez ve ezilen sayılır. Arka plan izninin olmaması ise iznin geri alınmasına benzer: sonraki güncellemeler hiç gelmez ve kayıp sayılır. İki durumda da uygulama bir hata görmez. Kullanıcıya “konumun neden güncellenmediği” sorusunun cevabı, uygulamanın hangi izne sahip olduğunu bilmesinden geçer.

Birden Fazla Anahtar

Şimdiye kadar tek bir kurye vardı ve en küçük aralık kuralı bütün güncellemelere tek bir sayaç gibi uygulanıyordu. İki kurye aynı sağlayıcıdan güncelleme aldığında bu hatalı olur: bir kuryenin güncellemesi, diğerinin güncellemesinin aralığı içinde kaldığı için düşürülebilir ve diğer kuryenin yerini bildiren tek güncelleme kaybolur. Doğrusu aralığı anahtar başına uygulamaktır.

// Keys.kt — en kucuk araligi her anahtara ayri uygular
fun sampleByKey(sent: List<Signal>, minGap: Int): List<Signal> =
    sent.groupBy { it.key }.values.flatMap { sample(it, minGap) }

İki kurye art arda güncelleme gönderiyor; aralık dört adım.

// Main.kt — aralik her kuryeye ayri uygulanir ve her kurye kendi yerini korur
fun main() {
    val sent = (19..26).map { Signal(if (it % 2 == 1) "konum.kurye1" else "konum.kurye2", it) }
    val received = sampleByKey(sent, minGap = 4)
    println("ulasan siralar: ${received.map { it.seq }.sorted()}")

    val arrivals = sent.map { Arrival("olay-${it.seq}", it, received) }
    arrivals.forEach { it.line() }
    countArrivals(arrivals)
}
ulasan siralar: [19, 20, 23, 24]
olay-19: anahtar=konum.kurye1 | kopya=1 -> birebir
olay-20: anahtar=konum.kurye2 | kopya=1 -> birebir
olay-21: anahtar=konum.kurye1 | kopya=0 -> ezilen
olay-22: anahtar=konum.kurye2 | kopya=0 -> ezilen
olay-23: anahtar=konum.kurye1 | kopya=1 -> birebir
olay-24: anahtar=konum.kurye2 | kopya=1 -> birebir
olay-25: anahtar=konum.kurye1 | kopya=0 -> kayip
olay-26: anahtar=konum.kurye2 | kopya=0 -> kayip
birebir: 4
yinelenen: 0
ezilen: 2
kayip: 2

Her kurye kendi sayacıyla ilerledi: ikisinin de ilk ve üçüncü güncellemesi birebir ulaştı, aradakiler ezilen oldu ve her kuryenin sonuncusu kayıp oldu. Ezilen güncellemenin yerini alan güncelleme aynı anahtarlıdır; bu yüzden bir kuryenin güncellemesi diğerinin yerini almış sayılmaz. Kayıp iki güncelleme, yani 25 ve 26, aralığın bedelidir: aralıktan sonra gelmeyen güncelleme ezilecek bir ardılı olmadığı için hiç ulaşmaz.

SY2. Model, iki kuryeyi iki ayrı anahtar olarak kurar ve güncellemeleri sırayla dağıtır. Platformda her konum isteği kendi aralığını taşır ve aynı sağlayıcıdan birden fazla dinleyici bağımsız aralıklarla güncelleme alabilir.

Aralık Bire İnince

Aralığın bire indirilmesi kuralı gevşetir: ardışık iki güncelleme arasında en az bir adım yeter ve bu her zaman sağlanır. Aynı kural, aralık değiştirilerek, ölçümün hiçbir güncellemeyi düşürmediğini gösterir.

// Main.kt — aralik bire inince butun guncellemeler birebir ulasir
fun main() {
    val sent = (9..12).map { Signal("konum.kurye", it) }
    val received = sample(sent, minGap = 1)
    val arrivals = sent.map { Arrival("olay-${it.seq}", it, received) }
    arrivals.forEach { it.line() }
    countArrivals(arrivals)
}
olay-9: anahtar=konum.kurye | kopya=1 -> birebir
olay-10: anahtar=konum.kurye | kopya=1 -> birebir
olay-11: anahtar=konum.kurye | kopya=1 -> birebir
olay-12: anahtar=konum.kurye | kopya=1 -> birebir
birebir: 4
yinelenen: 0
ezilen: 0
kayip: 0

Dört güncellemenin dördü birebir ulaştı. Bunun bedeli alıcıdadır: alıcı artık her güncellemeyi işlemek zorundadır. Hangi aralığın uygun olduğu uygulamanın kararıdır; kural yalnız sonucu sayar.

SY3. Model, alıcının işlem süresini sıfır kabul eder. Platformda yoğun bir alıcı geri çağrıyı geciktirebilir ve bu gecikmenin sonuçları modelde yoktur.

İki Eşik ve Dinleyicinin Ömrü

Platform kodundaki parça iki eşik taşıyordu: süre ve uzaklık. Sağlayıcı, ikisi birden sağlanmadan güncelleme vermez; kurye beş saniyede yalnızca iki metre ilerlediyse süre eşiği dolsa bile uzaklık eşiği dolmadığı için güncelleme gelmez. Modelin tek bir adım sayacı kullanması bu yüzden bir sadeleştirmedir. Duran bir kurye için gerçek sağlayıcı hiç güncelleme üretmez ve modeldeki “ezilen” ile “kayıp” ayrımı, durmanın kaybı sayılıp sayılmayacağı sorusunu da gündeme getirir. Durmak bir kayıp değildir: ortada gönderilmiş bir olay yoktur.

Dinleyicinin ömrü ikinci bir kaynaktır. Geri çağrıyı kaydeden uygulama, ekran kapandığında kaydı kaldırmazsa sağlayıcı güncelleme üretmeye devam eder ve alıcı, kullanıcının görmediği bir ekrana işlem yapar. Tersine, kaydı erken kaldıran uygulama kullanıcı geri döndüğünde yeni bir kayıt açana kadar güncelleme almaz ve bu aralıktaki güncellemeler hiç üretilmez. Ders boyunca ölçtüğümüz kayıp ile bu kayıp arasındaki fark, kuralın görebildiği şeydedir: kural yalnızca gönderilmiş olayları sayar; kayıt kaldırıldığı için hiç üretilmeyen bir güncelleme, model açısından, hiç gönderilmemiştir.

Bu ayrımın pratik sonucu şudur: bir güncellemenin gelmemesi, her zaman bir teslim hatası değildir. Uygulama önce güncellemenin üretilip üretilmediğine, sonra üretilen güncellemenin alıcıya ulaşıp ulaşmadığına bakmalıdır. İlk soru sağlayıcının ve kaydın, ikinci soru ise bu dersin ölçtüğü kuralların sorusudur.

Yaygın Yanılgılar

“En küçük aralık güncelleme sıklığını garanti eder.” Aralık bir alt sınırdır, bir söz değildir. Sağlayıcı aralıktan seyrek güncelleme verebilir; pil tasarrufu, zayıf sinyal ya da arka plana geçiş bunu yapar. Aralığı küçültmek güncelleme sayısını artırmaz; yalnızca düşürülecek güncelleme sayısını azaltır.

“Daha çok güncelleme daha iyi konum demektir.” Her güncelleme alıcıda işlenir. Gereğinden küçük bir aralık, alıcıyı ve pili yorar; ölçümde aralık bire inince bütün güncellemeler birebir ulaştı ama bunun bedeli alıcının her birini işlemesiydi.

“Kullanıcı izni bir kez verdi, her zaman geçerlidir.” İzin ayarlardan geri alınabilir ve bazı sürümlerde belirli bir süre sonra kendiliğinden sıfırlanabilir. Uygulama her güncelleme isteğinden önce izin durumunu denetlemelidir. İzin yokken geri çağrıyı beklemek, ölçümde olduğu gibi kayıp güncelleme biriktirmekten başka bir şey vermez.

“Kullanıcı durduysa güncelleme kaybolmuştur.” Duran bir kullanıcı için sağlayıcı yeni güncelleme üretmez; ortada gönderilmiş bir olay olmadığı için kural bir kayıp görmez. Aynı sessizlik, kayıt kaldırıldığında da görülür ve ikisini ayırmak uygulamanın işidir.

“Harita görünümü konum güncellemesini teslim eder.” Harita yalnızca elindeki konumu çizer. Güncelleme alıcıya ulaşmadıysa harita eski yeri gösterir ve bu bir çizim hatası olarak görünür, oysa kayıp daha önce, sağlayıcı ile alıcı arasında olmuştur.

Sınırlayıcı Ölçüm

Aralık kuralı güncellemenin ulaşmasını yalnızca seyreltir. İzin ise ulaşmanın önkoşuludur. Kullanıcı izni ayarlardan geri aldığında sağlayıcı o adımdan sonra güncelleme vermez ve aralık hangi sayıda olursa olsun sonraki güncellemeler gelmez.

// Main.kt — izin geri alinca sonraki guncellemeler ulasmaz
fun main() {
    val sent = (13..18).map { Signal("konum.kurye", it) }
    val received = revoke(sample(sent, minGap = 2), revokedAt = 16)
    println("ulasan siralar: ${received.map { it.seq }}")

    val arrivals = sent.map { Arrival("olay-${it.seq}", it, received) }
    arrivals.forEach { it.line() }
    countArrivals(arrivals)
}
ulasan siralar: [13, 15]
olay-13: anahtar=konum.kurye | kopya=1 -> birebir
olay-14: anahtar=konum.kurye | kopya=0 -> ezilen
olay-15: anahtar=konum.kurye | kopya=1 -> birebir
olay-16: anahtar=konum.kurye | kopya=0 -> kayip
olay-17: anahtar=konum.kurye | kopya=0 -> kayip
olay-18: anahtar=konum.kurye | kopya=0 -> kayip
birebir: 2
yinelenen: 0
ezilen: 1
kayip: 3

13 ve 15 numaralı güncellemeler ulaştı, 14 ise 15’in yerini aldığı için ezilen sayıldı. İzin 16 numaralı adımda geri alındığı için 16, 17 ve 18 kayıp oldu: sonrasında aynı anahtarla hiçbir güncelleme gelmedi. Kural, kaybın nedeninin geri alınan izin olduğunu görmez. Bunu bilmek için uygulamanın izin durumunu ayrıca denetlemesi gerekir.

SY4. Model, iznin geri alınmasını tek bir adımda ve kesin olarak kurar. Platformda izin geri alındığında uygulama sonlandırılabilir, kesin izin yaklaşık izne düşürülebilir ve kullanıcı izni sonra yeniden verebilir; bunlar modelde yoktur.

Özet

  • Bu dersin teslimi: ezilen. En küçük aralık kuralı arada kalan konum güncellemelerini düşürür ve yerlerini aynı anahtarlı sonraki güncelleme alır.
  • Sekiz güncellemeden dördü ezilen oldu, üçü birebir ulaştı, sonuncusu kayıp oldu: birebir 3, ezilen 4, kayip 1.
  • Aralık her anahtara ayrı uygulanınca iki kuryenin ilk ve üçüncü güncellemeleri birebir ulaştı, aradakiler ezilen oldu, ikisinin sonuncusu kayıp oldu: birebir 4, ezilen 2, kayip 2.
  • Aralık bire inince dört güncellemenin dördü birebir ulaştı; bedel alıcının her güncellemeyi işlemesidir.
  • İzin geri alındıktan sonra üretilen üç güncelleme kayıp oldu: kayip 3. Kural nedeni görmez.
  • Kesin ve yaklaşık konum ayrı izinlerdir ve kural duyarlığı görmez; harita görünümü bir teslim sorusu değildir ve ölçülmedi.

Sonraki Adım

Bu derste olay sürekli bir akıştı ve kural arada kalanları düşürdü. Kamerada olay tek bir kullanıcı eyleminden doğar ve her eylem tek bir sonuç vermelidir. Sıradaki ders, Kamera ve Medya, deklanşöre iki kez dokunulduğunda iki ayrı olayın nasıl ulaştığını ölçer.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ ↵ Esc gezin · aç · kapat