Bu codelab, Android Kotlin Hakkında Temel Bilgiler kursunun bir parçasıdır. Bu kurstan en iyi şekilde yararlanmak için codelab'leri sırayla tamamlamanızı öneririz. Kursla ilgili tüm codelab'ler Android Kotlin Hakkında Temel Bilgiler codelab'leri açılış sayfasında listelenir.
Giriş
Uygulamanızda kusursuz bir kullanıcı deneyimi oluşturmak için en önemli önceliklerden biri, kullanıcı arayüzünün her zaman duyarlı olmasını ve sorunsuz çalışmasını sağlamaktır. Kullanıcı arayüzü performansını iyileştirmenin bir yolu, uzun süren görevleri (ör. veritabanı işlemleri) arka plana taşımaktır.
Bu codelab'de, TrackMySleepQuality uygulamasının kullanıcıya yönelik bölümünü Kotlin eşyordamlarını kullanarak veritabanı işlemlerini ana iş parçacığından uzakta gerçekleştirecek şekilde uygulayacaksınız.
Bilmeniz gerekenler
Aşağıdaki konular hakkında bilgi sahibi olmanız gerekir:
- Etkinlik, parçalar, görünümler ve tıklama işleyicileri kullanarak temel bir kullanıcı arayüzü (UI) oluşturma.
- Parçalar arasında gezinme ve parçalar arasında basit veriler aktarmak için
safeArgs
kullanma. - Modelleri, model fabrikalarını, dönüşümleri ve
LiveData
görüntüleyin. Room
veritabanı oluşturma, DAO oluşturma ve varlıkları tanımlama- İş parçacığı oluşturma ve çoklu işleme kavramlarına aşina olmanız faydalıdır.
Neler öğreneceksiniz?
- Android'de ileti dizilerinin işleyiş şekli.
- Veritabanı işlemlerini ana iş parçacığından uzaklaştırmak için Kotlin eşyordamlarını kullanma
- Biçimlendirilmiş verileri
TextView
içinde görüntüleme
Yapacaklarınız
- TrackMySleepQuality uygulamasını, verileri veritabanında ve veritabanından toplayacak, depolayacak ve görüntüleyecek şekilde genişletin.
- Uzun süren veritabanı işlemlerini arka planda çalıştırmak için eş yordamları kullanın.
- Gezinmeyi ve snackbar'ın gösterilmesini tetiklemek için
LiveData
kullanın. - Düğmeleri etkinleştirmek ve devre dışı bırakmak için
LiveData
kısayolunu kullanın.
Bu codelab'de TrackMySleepQuality uygulamasının görünüm modeli, eşzamanlı rutinler ve veri görüntüleme bölümlerini oluşturacaksınız.
Uygulama, aşağıdaki şekilde gösterildiği gibi parçalarla temsil edilen iki ekrana sahiptir.
Solda gösterilen ilk ekranda izlemeyi başlatma ve durdurma düğmeleri bulunur. Ekranda kullanıcının tüm uyku verileri gösterilir. Temizle düğmesi, uygulamanın kullanıcı için topladığı tüm verileri kalıcı olarak siler.
Sağda gösterilen ikinci ekranda uyku kalitesi derecesi seçilir. Uygulamada puan sayısal olarak gösterilir. Uygulama, geliştirme amacıyla hem yüz simgelerini hem de bunların sayısal karşılıklarını gösterir.
Kullanıcının akışı şu şekildedir:
- Kullanıcı uygulamayı açar ve uyku takibi ekranı gösterilir.
- Kullanıcı, Başlat düğmesine dokunur. Bu işlev, başlangıç zamanını kaydeder ve görüntüler. Başlat düğmesi devre dışı, Durdur düğmesi ise etkin olur.
- Kullanıcı, Durdur düğmesine dokunur. Bu işlem, bitiş zamanını kaydeder ve uyku kalitesi ekranını açar.
- Kullanıcı, uyku kalitesi simgesi seçer. Ekran kapanır ve takip ekranında uyku bitiş saati ile uyku kalitesi gösterilir. Durdur düğmesi devre dışı, Başlat düğmesi ise etkin olur. Uygulama başka bir geceye hazır.
- Veritabanında veri olduğunda Temizle düğmesi etkinleştirilir. Kullanıcı Temizle düğmesine dokunduğunda tüm verileri geri dönüşü olmayacak şekilde silinir. "Emin misiniz?" mesajı gösterilmez.
Bu uygulama, tam mimari bağlamında aşağıda gösterildiği gibi basitleştirilmiş bir mimari kullanır. Uygulama yalnızca aşağıdaki bileşenleri kullanır:
- Kullanıcı arayüzü denetleyicisi
- Modeli ve
LiveData
görüntüleme - Room veritabanı
Bu görevde, biçimlendirilmiş uyku takibi verilerini görüntülemek için TextView
kullanacaksınız. (Bu nihai arayüz değildir. Daha iyi bir yöntemi başka bir codelab'de öğreneceksiniz.)
Önceki codelab'de oluşturduğunuz TrackMySleepQuality uygulamasıyla devam edebilir veya bu codelab'in başlangıç uygulamasını indirebilirsiniz.
1. adım: Başlangıç uygulamasını indirip çalıştırın
- GitHub'dan TrackMySleepQuality-Coroutines-Starter uygulamasını indirin.
- Uygulamayı oluşturup çalıştırın. Uygulama,
SleepTrackerFragment
parçası için kullanıcı arayüzünü gösteriyor ancak veri göstermiyor. Düğmeler dokunmaya yanıt vermiyor.
2. adım: Kodu inceleyin
Bu codelab'in başlangıç kodu, 6.1 Create a Room database codelab'in çözüm kodu ile aynıdır.
- res/layout/activity_main.xml. Bu düzende
nav_host_fragment
parçası bulunuyor. Ayrıca<merge>
etiketine dikkat edin.
Düzenleri dahil ederken gereksiz düzenleri ortadan kaldırmak içinmerge
etiketi kullanılabilir. Bu etiketi kullanmanız önerilir. Gereksiz bir düzene örnek olarak ConstraintLayout > LinearLayout > TextView verilebilir. Burada sistem, LinearLayout'ı ortadan kaldırabilir. Bu tür bir optimizasyon, görünüm hiyerarşisini basitleştirebilir ve uygulama performansını artırabilir. - navigation klasöründe navigation.xml dosyasını açın. İki parça ve bunları birbirine bağlayan gezinme işlemlerini görebilirsiniz.
- layout klasöründe, uyku izleyici parçasının XML düzenini görmek için bu parçayı çift tıklayın. Aşağıdakilere dikkat edin:
- Düzen verileri, veri bağlamayı etkinleştirmek için
<layout>
öğesine sarılır. ConstraintLayout
ve diğer görünümler,<layout>
öğesinin içinde düzenlenir.- Dosyada
<data>
yer tutucu etiketi var.
Başlangıç uygulaması, kullanıcı arayüzü için boyutlar, renkler ve stil de sağlar. Uygulama, Room
veritabanı, DAO ve SleepNight
tüzel kişiliği içeriyor. Önceki codelab'i tamamlamadıysanız kodun bu yönlerini kendi başınıza incelediğinizden emin olun.
Artık bir veritabanınız ve kullanıcı arayüzünüz olduğuna göre veri toplamanız, verileri veritabanına eklemeniz ve verileri görüntülemeniz gerekir. Tüm bu işlemler görünüm modelinde yapılır. Uyku izleyici görünüm modeliniz, düğme tıklamalarını işler, DAO aracılığıyla veritabanıyla etkileşimde bulunur ve LiveData
aracılığıyla kullanıcı arayüzüne veri sağlar. Tüm veritabanı işlemleri ana kullanıcı arayüzü iş parçacığından uzakta çalıştırılmalıdır. Bunu da coroutine'leri kullanarak yapacaksınız.
1. adım: SleepTrackerViewModel'ı ekleyin
- sleeptracker paketinde SleepTrackerViewModel.kt dosyasını açın.
- Başlangıç uygulamasında sizin için sağlanan ve aşağıda da gösterilen
SleepTrackerViewModel
sınıfını inceleyin. DersinAndroidViewModel()
sürdüğünü unutmayın. Bu sınıf,ViewModel
ile aynıdır ancak uygulama bağlamını parametre olarak alır ve özellik olarak kullanılabilir hale getirir. Bu bilgiye daha sonra ihtiyacınız olacaktır.
class SleepTrackerViewModel(
val database: SleepDatabaseDao,
application: Application) : AndroidViewModel(application) {
}
2. adım: SleepTrackerViewModelFactory'yi ekleyin
- sleeptracker paketinde SleepTrackerViewModelFactory.kt dosyasını açın.
- Fabrika için sağlanan ve aşağıda gösterilen kodu inceleyin:
class SleepTrackerViewModelFactory(
private val dataSource: SleepDatabaseDao,
private val application: Application) : ViewModelProvider.Factory {
@Suppress("unchecked_cast")
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(SleepTrackerViewModel::class.java)) {
return SleepTrackerViewModel(dataSource, application) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
Aşağıdakileri göz önünde bulundurun:
- Belirtilen
SleepTrackerViewModelFactory
,ViewModel
ile aynı bağımsız değişkeni alır veViewModelProvider.Factory
'yi genişletir. - Fabrikanın içinde, herhangi bir sınıf türünü bağımsız değişken olarak alan ve
ViewModel
döndürencreate()
geçersiz kılınır. create()
gövdesinde,SleepTrackerViewModel
sınıfının mevcut olup olmadığı kontrol edilir ve mevcutsa sınıfın bir örneği döndürülür. Aksi takdirde kod, istisna oluşturur.
3. adım: SleepTrackerFragment'ı güncelleyin
SleepTrackerFragment
içinde uygulama bağlamına referans alın. ReferansıonCreateView()
içine,binding
altına yerleştirin. Bu parçanın eklendiği uygulamaya, görünüm modeli fabrika sağlayıcısına aktarılacak bir referansınızın olması gerekir.
requireNotNull
Kotlin işlevi, değernull
iseIllegalArgumentException
oluşturur.
val application = requireNotNull(this.activity).application
- DAO'ya yapılan bir referans aracılığıyla veri kaynağınıza referans vermeniz gerekir.
onCreateView()
içinde,return
öğesinden önce birdataSource
tanımlayın. Veritabanının DAO'sunu referans almak içinSleepDatabase.getInstance(application).sleepDatabaseDao
kullanın.
val dataSource = SleepDatabase.getInstance(application).sleepDatabaseDao
onCreateView()
içinde,return
öğesinden önceviewModelFactory
öğesinin bir örneğini oluşturun.dataSource
veapplication
sınavlarını geçmeniz gerekir.
val viewModelFactory = SleepTrackerViewModelFactory(dataSource, application)
- Artık bir fabrikanız olduğuna göre
SleepTrackerViewModel
için bir referans alın.SleepTrackerViewModel::class.java
parametresi, bu nesnenin çalışma zamanı Java sınıfını ifade eder.
val sleepTrackerViewModel =
ViewModelProviders.of(
this, viewModelFactory).get(SleepTrackerViewModel::class.java)
- Tamamlanmış kodunuz şu şekilde görünmelidir:
// Create an instance of the ViewModel Factory.
val dataSource = SleepDatabase.getInstance(application).sleepDatabaseDao
val viewModelFactory = SleepTrackerViewModelFactory(dataSource, application)
// Get a reference to the ViewModel associated with this fragment.
val sleepTrackerViewModel =
ViewModelProviders.of(
this, viewModelFactory).get(SleepTrackerViewModel::class.java)
Şu ana kadarki onCreateView()
yöntemi:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Get a reference to the binding object and inflate the fragment views.
val binding: FragmentSleepTrackerBinding = DataBindingUtil.inflate(
inflater, R.layout.fragment_sleep_tracker, container, false)
val application = requireNotNull(this.activity).application
val dataSource = SleepDatabase.getInstance(application).sleepDatabaseDao
val viewModelFactory = SleepTrackerViewModelFactory(dataSource, application)
val sleepTrackerViewModel =
ViewModelProviders.of(
this, viewModelFactory).get(SleepTrackerViewModel::class.java)
return binding.root
}
4. adım: Görünüm modeli için veri bağlama ekleyin
Temel ViewModel
yerindeyken ViewModel
ile kullanıcı arayüzünü bağlamak için SleepTrackerFragment
içinde veri bağlamayı ayarlamayı tamamlamanız gerekir.
fragment_sleep_tracker.xml
düzen dosyasında:
<data>
bloğunun içinde,SleepTrackerViewModel
sınıfına referans veren bir<variable>
oluşturun.
<data>
<variable
name="sleepTrackerViewModel"
type="com.example.android.trackmysleepquality.sleeptracker.SleepTrackerViewModel" />
</data>
SleepTrackerFragment
içinde:
- Bağlamanın yaşam döngüsü sahibi olarak mevcut etkinliği ayarlayın. Bu kodu
onCreateView()
yönteminin içine,return
ifadesinden önce ekleyin:
binding.setLifecycleOwner(this)
sleepTrackerViewModel
bağlama değişkeninisleepTrackerViewModel
öğesine atayın. Bu koduonCreateView()
içine,SleepTrackerViewModel
öğesini oluşturan kodun altına yerleştirin:
binding.sleepTrackerViewModel = sleepTrackerViewModel
- Bağlama nesnesini yeniden oluşturmanız gerektiğinden muhtemelen bir hata görürsünüz. Hatayı gidermek için projeyi temizleyip yeniden oluşturun.
- Son olarak, her zaman olduğu gibi kodunuzun hatasız şekilde oluşturulduğundan ve çalıştığından emin olun.
Kotlin'de uzun süren görevleri zarif ve verimli bir şekilde işlemek için coroutine'ler kullanılır. Kotlin coroutines, geri çağırmaya dayalı kodu sıralı koda dönüştürmenize olanak tanır. Sırayla yazılan kodlar genellikle daha kolay okunur ve hatta istisnalar gibi dil özelliklerini kullanabilir. Sonuç olarak, eş yordamlar ve geri çağırmalar aynı şeyi yapar: Uzun süren bir görevden sonuç alınana kadar bekler ve yürütmeye devam eder.
Coroutine'lar aşağıdaki özelliklere sahiptir:
- Coroutines eşzamansızdır ve engellemez.
- Eş yordamlar, eşzamansız kodu sıralı hale getirmek için suspend işlevlerini kullanır.
Coroutine'lar eşzamansızdır.
Bir eş yordam, programınızın ana yürütme adımlarından bağımsız olarak çalışır. Bu işlem paralel olarak veya ayrı bir işlemcide yapılabilir. Ayrıca, uygulamanın geri kalanı giriş beklerken siz de biraz işlem yapabilirsiniz. Asenkronun önemli yönlerinden biri, sonucu açıkça beklemediğiniz sürece kullanılamayacağını varsaymamanızdır.
Örneğin, araştırma yapmayı gerektiren bir sorunuz olduğunu ve bir iş arkadaşınızdan cevabı bulmasını istediğinizi varsayalım. Bu kişiler, "eşzamansız" ve "ayrı bir iş parçacığında" çalışıyormuş gibi davranarak bu işi yapmaya devam eder. Meslektaşınız geri gelip yanıtı söyleyene kadar, yanıta bağlı olmayan diğer işlerinizi yapmaya devam edebilirsiniz.
Coroutine'ler engellemez.
Engellememe , bir eş yordamın ana iş parçacığını veya kullanıcı arayüzü iş parçacığını engellemediği anlamına gelir. Bu nedenle, kullanıcı arayüzü etkileşimi her zaman öncelikli olduğundan kullanıcılar, eş yordamlarla her zaman mümkün olan en sorunsuz deneyimi yaşar.
Eş yordamlar, eşzamansız kodu sıralı hale getirmek için askıya alma işlevlerini kullanır.
suspend
anahtar kelimesi, Kotlin'in bir işlevi veya işlev türünü coroutine'ler için kullanılabilir olarak işaretleme yöntemidir. Bir coroutine, suspend
ile işaretlenmiş bir işlevi çağırdığında, normal bir işlev çağrısında olduğu gibi işlev döndürülene kadar engellemek yerine sonuç hazır olana kadar yürütmeyi askıya alır. Ardından, sonuçla birlikte eş yordam kaldığı yerden devam eder.
Coroutine askıya alınmış ve sonuç beklerken üzerinde çalıştığı iş parçacığının engellemesini kaldırır. Bu sayede diğer işlevler veya eş yordamlar çalışabilir.
suspend
anahtar kelimesi, kodun üzerinde çalıştığı iş parçacığını belirtmez. Askıya alma işlevi, arka plan iş parçacığında veya ana iş parçacığında çalışabilir.
Kotlin'de eş yordamları kullanmak için üç şeye ihtiyacınız vardır:
- Bir iş
- Görev dağıtıcı
- Kapsam
İş: İş, temelde iptal edilebilen her şeydir. Her eş yordamın bir işi vardır ve eş yordamı iptal etmek için bu işi kullanabilirsiniz. İşler, üst-alt hiyerarşileri şeklinde düzenlenebilir. Bir üst işin iptal edilmesi, işin tüm alt öğelerini anında iptal eder. Bu, her eş yordamı manuel olarak iptal etmekten çok daha kolaydır.
Dispatcher: Dispatcher, çeşitli iş parçacıklarında çalışacak şekilde eş yordamlar gönderir. Örneğin, Dispatcher.Main
ana iş parçacığında görevleri çalıştırır ve Dispatcher.IO
engelleme G/Ç görevlerini ortak bir iş parçacığı havuzuna yükler.
Kapsam: Bir eş yordamın kapsamı, eş yordamın çalıştığı bağlamı tanımlar. Kapsam, eşzamanlı yordamın işi ve dağıtıcı hakkındaki bilgileri birleştirir. Kapsamlar, eşzamanlı rutinleri takip eder. Bir eşzamanlı rutin başlattığınızda bu rutin "bir kapsamdadır". Yani, hangi kapsamın eşzamanlı rutini takip edeceğini belirtmişsinizdir.
Kullanıcının uyku verileriyle aşağıdaki şekillerde etkileşime girmesini istiyorsanız:
- Kullanıcı Başlat düğmesine dokunduğunda uygulama yeni bir uyku gecesi oluşturur ve uyku gecesini veritabanında saklar.
- Kullanıcı Durdur düğmesine dokunduğunda uygulama, geceyi bitiş zamanıyla günceller.
- Kullanıcı Temizle düğmesine dokunduğunda uygulama, veritabanındaki verileri siler.
Bu veritabanı işlemleri uzun sürebileceğinden ayrı bir iş parçacığında çalıştırılmalıdır.
1. adım: Veritabanı işlemleri için eş yordamlar ayarlayın
Uyku İzleyici uygulamasında Başlat düğmesine dokunulduğunda, SleepTrackerViewModel
içinde bir işlev çağırarak SleepNight
öğesinin yeni bir örneğini oluşturmak ve bu örneği veritabanında depolamak istiyorsunuz.
Düğmelerden birine dokunulduğunda SleepNight
oluşturma veya güncelleme gibi bir veritabanı işlemi tetiklenir. Bu ve diğer nedenlerden dolayı, uygulamanın düğmeleri için tıklama işleyicilerini uygulamak üzere coroutine'leri kullanırsınız.
- Uygulama düzeyindeki
build.gradle
dosyasını açın ve coroutine'lerin bağımlılıklarını bulun. Coroutine'ları kullanmak için sizin adınıza eklenen şu bağımlılıkları kullanmanız gerekir.$coroutine_version
, projebuild.gradle
dosyasındacoroutine_version =
'1.0.0'
olarak tanımlanır.
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutine_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutine_version"
SleepTrackerViewModel
dosyasını açın.- Sınıfın gövdesinde
viewModelJob
öğesini tanımlayın veJob
öğesinin bir örneğini atayın. BuviewModelJob
, görünüm modeli artık kullanılmadığında ve yok edildiğinde bu görünüm modeli tarafından başlatılan tüm eşzamanlı rutinleri iptal etmenize olanak tanır. Bu şekilde, geri dönülecek yeri olmayan coroutine'ler oluşturmazsınız.
private var viewModelJob = Job()
- Sınıf gövdesinin sonunda
onCleared()
işlevini geçersiz kılın ve tüm eşzamanlı rutinleri iptal edin.ViewModel
yok edildiğindeonCleared()
çağrılır.
override fun onCleared() {
super.onCleared()
viewModelJob.cancel()
}
viewModelJob
tanımının hemen altında, coroutine'ler için biruiScope
tanımlayın. Kapsam, eş yordamın hangi iş parçacığında çalışacağını belirler ve iş hakkında da bilgi sahibi olması gerekir. Kapsam almak içinCoroutineScope
örneği isteyin ve gönderici ile işi iletin.
Dispatchers.Main
kullanmak, uiScope
içinde başlatılan eş yordamların ana iş parçacığında çalışacağı anlamına gelir. Bu, ViewModel
tarafından başlatılan birçok eş yordam için mantıklıdır. Çünkü bu eş yordamlar bazı işlemler gerçekleştirdikten sonra kullanıcı arayüzünün güncellenmesine neden olur.
private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)
uiScope
tanımının altında, mevcut geceyi tutmak içintonight
adlı bir değişken tanımlayın. Verileri gözlemleyip değiştirebilmeniz gerektiğinden değişkeniMutableLiveData
yapın.
private var tonight = MutableLiveData<SleepNight?>()
tonight
değişkenini mümkün olan en kısa sürede başlatmak içintonight
tanımının altında birinit
bloğu oluşturun veinitializeTonight()
işlevini çağırın.initializeTonight()
değerini sonraki adımda tanımlarsınız.
init {
initializeTonight()
}
init
bloğunun altınainitializeTonight()
kodunu uygulayın.uiScope
içinde bir eş yordam başlatın. İçeride,tonight
için değerigetTonightFromDatabase()
çağırarak veritabanından alın ve değeritonight.value
'ye atayın.getTonightFromDatabase()
değerini sonraki adımda tanımlarsınız.
private fun initializeTonight() {
uiScope.launch {
tonight.value = getTonightFromDatabase()
}
}
getTonightFromDatabase()
'yi uygulama. Mevcut birSleepNight
başlatılmamışsa bunu boş değer atanabilir birSleepNight
döndürenprivate suspend
işlevi olarak tanımlayın. Bu durumda, işlevin bir değer döndürmesi gerektiğinden hata alırsınız.
private suspend fun getTonightFromDatabase(): SleepNight? { }
-
getTonightFromDatabase()
işlevinin gövdesinde,Dispatchers.IO
bağlamında çalışan bir ortak yordamdan sonucu döndürün. Veritabanından veri almak bir G/Ç işlemidir ve kullanıcı arayüzüyle ilgisi yoktur. Bu nedenle G/Ç dağıtıcısını kullanın.
return withContext(Dispatchers.IO) {}
- Döndürme bloğunda, coroutine'in veritabanından bu geceyi (en yeni gece) almasına izin verin. Başlangıç ve bitiş zamanları aynı değilse (yani gece tamamlanmışsa)
null
değerini döndürün. Aksi takdirde geceyi döndürür.
var night = database.getTonight()
if (night?.endTimeMilli != night?.startTimeMilli) {
night = null
}
night
Tamamlanmış getTonightFromDatabase()
askıya alma işleviniz şu şekilde görünmelidir. Başka hata olmamalıdır.
private suspend fun getTonightFromDatabase(): SleepNight? {
return withContext(Dispatchers.IO) {
var night = database.getTonight()
if (night?.endTimeMilli != night?.startTimeMilli) {
night = null
}
night
}
}
2. adım: Başlat düğmesi için tıklama işleyicisini ekleyin
Artık Başlat düğmesinin tıklama işleyicisi olan onStartTracking()
işlevini uygulayabilirsiniz. Yeni bir SleepNight
oluşturmanız, bunu veritabanına eklemeniz ve tonight
'ye atamanız gerekir. onStartTracking()
yapısı, initializeTonight()
yapısına çok benzeyecek.
onStartTracking()
için işlev tanımıyla başlayın. Tıklama işleyicilerinionCleared()
öğesinin üstüneSleepTrackerViewModel
dosyasına yerleştirebilirsiniz.
fun onStartTracking() {}
onStartTracking()
içinde, devam etmek ve kullanıcı arayüzünü güncellemek için bu sonuca ihtiyacınız olduğundanuiScope
içinde bir eş yordam başlatın.
uiScope.launch {}
- Coroutine başlatma işlemi içinde, geçerli zamanı başlangıç zamanı olarak yakalayan yeni bir
SleepNight
oluşturun.
val newNight = SleepNight()
- Coroutine başlatma işlemi içindeyken
insert()
işlevini çağırarak veritabanınanewNight
ekleyin. Buinsert()
askıya alma işlevini henüz tanımlamadığınız için bir hata görürsünüz. (Bu, aynı ada sahip DAO işlevi değildir.)
insert(newNight)
- Ayrıca, coroutine başlatma işlemi içinde
tonight
değerini güncelleyin.
tonight.value = getTonightFromDatabase()
onStartTracking()
'nın altında,insert()
işlevini bağımsız değişken olarakSleepNight
alan birprivate suspend
işlevi olarak tanımlayın.
private suspend fun insert(night: SleepNight) {}
insert()
gövdesi için I/O bağlamında bir eşzamanlı rutin başlatın ve DAO'daninsert()
çağırarak geceyi veritabanına ekleyin.
withContext(Dispatchers.IO) {
database.insert(night)
}
fragment_sleep_tracker.xml
düzen dosyasında, daha önce ayarladığınız veri bağlama özelliğini kullanarakonStartTracking()
için tıklama işleyicisinistart_button
öğesine ekleyin.@{() ->
işlev gösterimi, bağımsız değişken almayan vesleepTrackerViewModel
içindeki tıklama işleyicisini çağıran bir lambda işlevi oluşturur.
android:onClick="@{() -> sleepTrackerViewModel.onStartTracking()}"
- Uygulamanızı derleyip çalıştırın. Başlat düğmesine dokunun. Bu işlemle veri oluşturulur ancak henüz herhangi bir şey göremezsiniz. Bunu bir sonraki adımda düzeltirsiniz.
fun someWorkNeedsToBeDone { uiScope.launch { suspendFunction() } } suspend fun suspendFunction() { withContext(Dispatchers.IO) { longrunningWork() } }
3. adım: Verileri görüntüleyin
SleepTrackerViewModel
içinde, nights
değişkeni LiveData
değerine başvurur. Bunun nedeni, DAO'daki getAllNights()
değerinin LiveData
döndürmesidir.
Bu, veritabanındaki veriler her değiştiğinde Room
nights
'nin en son verileri gösterecek şekilde güncellendiği bir Room
özelliğidir.LiveData
LiveData
değerini hiçbir zaman açıkça ayarlamanız veya güncellemeniz gerekmez. Room
, verileri veritabanasıyla eşleşecek şekilde günceller.
Ancak nights
öğesini bir metin görünümünde gösterirseniz nesne referansı gösterilir. Nesnenin içeriğini görmek için verileri biçimlendirilmiş bir dizeye dönüştürün. Veritabanından yeni veriler alındığında Transformation
her seferinde yürütülen bir nights
haritası kullanın.
Util.kt
dosyasını açın veformatNights()
ile ilişkiliimport
ifadelerinin tanımı için kodun yorumunu kaldırın. Android Studio'da yorum satırı olarak işaretlenmiş kodu kaldırmak için//
ile işaretlenmiş tüm kodu seçin veCmd+/
veyaControl+/
tuşuna basın.formatNights()
işlevinin, HTML biçimlendirmeli bir dize olanSpanned
türünü döndürdüğünü unutmayın.- strings.xml dosyasını açın. Uyku verilerini görüntülemek için dize kaynaklarını biçimlendirmek üzere
CDATA
kullanımına dikkat edin. - SleepTrackerViewModel'i açın.
SleepTrackerViewModel
sınıfında,uiScope
tanımının altındanights
adlı bir değişken tanımlayın. Veritabanındaki tüm geceleri alıpnights
değişkenine atayın.
private val nights = database.getAllNights()
nights
tanımının hemen altına,nights
öğesininightsString
öğesine dönüştürecek kodu ekleyin.Util.kt
sınıfındakiformatNights()
işlevini kullanın.
nights
öğesiniTransformations
sınıfındakimap()
işlevine iletin. Dize kaynaklarınıza erişmek için eşleme işleviniformatNights()
olarak tanımlayın.nights
veResources
nesnesi sağlayın.
val nightsString = Transformations.map(nights) { nights ->
formatNights(nights, application.resources)
}
fragment_sleep_tracker.xml
düzen dosyasını açın.TextView
içinde,android:text
özelliğinde kaynak dizesini artıknightsString
referansıyla değiştirebilirsiniz.
"@{sleepTrackerViewModel.nightsString}"
- Kodunuzu yeniden oluşturun ve uygulamayı çalıştırın. Başlangıç zamanlarıyla birlikte tüm uyku verileriniz artık gösterilmelidir.
- Başlat düğmesine birkaç kez daha dokunduğunuzda daha fazla veri görürsünüz.
Sonraki adımda, Durdur düğmesi için işlevselliği etkinleştirirsiniz.
4. adım: Durdur düğmesi için tıklama işleyicisini ekleyin
Önceki adımdakiyle aynı kalıbı kullanarak SleepTrackerViewModel.
içindeki Stop (Durdur) düğmesi için tıklama işleyicisini uygulayın.
onStopTracking()
öğesiniViewModel
listesine ekleyin.uiScope
içinde bir coroutine başlatın. Bitiş zamanı henüz ayarlanmadıysaendTimeMilli
değerini mevcut sistem zamanına ayarlayın ve gece verileriyleupdate()
işlevini çağırın.
Kotlin'dereturn@
label
söz dizimi, iç içe yerleştirilmiş birkaç işlev arasında bu ifadenin döndürdüğü işlevi belirtir.
fun onStopTracking() {
uiScope.launch {
val oldNight = tonight.value ?: return@launch
oldNight.endTimeMilli = System.currentTimeMillis()
update(oldNight)
}
}
update()
öğesini,insert()
öğesini uygularken kullandığınız kalıpla aynı şekilde uygulayın.
private suspend fun update(night: SleepNight) {
withContext(Dispatchers.IO) {
database.update(night)
}
}
- Tıklama işleyicisini kullanıcı arayüzüne bağlamak için
fragment_sleep_tracker.xml
düzen dosyasını açın ve tıklama işleyicisinistop_button
öğesine ekleyin.
android:onClick="@{() -> sleepTrackerViewModel.onStopTracking()}"
- Uygulamanızı derleyip çalıştırın.
- Başlat'a ve ardından Durdur'a dokunun. Başlangıç zamanı, bitiş zamanı, değeri olmayan uyku kalitesi ve uyku süresini görürsünüz.
5. adım: Temizle düğmesi için tıklama işleyicisini ekleyin
- Benzer şekilde,
onClear()
veclear()
işaretlemelerini uygulayın.
fun onClear() {
uiScope.launch {
clear()
tonight.value = null
}
}
suspend fun clear() {
withContext(Dispatchers.IO) {
database.clear()
}
}
- Tıklama işleyicisini kullanıcı arayüzüne bağlamak için
fragment_sleep_tracker.xml
öğesini açın ve tıklama işleyicisiniclear_button
öğesine ekleyin.
android:onClick="@{() -> sleepTrackerViewModel.onClear()}"
- Uygulamanızı derleyip çalıştırın.
- Tüm verileri silmek için Temizle'ye dokunun. Ardından, yeni veriler oluşturmak için Başlat ve Durdur'a dokunun.
Android Studio projesi: TrackMySleepQualityCoroutines
- Uygulamanın kullanıcı arayüzü mimarisini ayarlamak için
ViewModel
,ViewModelFactory
ve veri bağlamayı kullanın. - Kullanıcı arayüzünün sorunsuz çalışmasını sağlamak için tüm veritabanı işlemleri gibi uzun süren görevlerde eş yordamları kullanın.
- Coroutines eşzamansızdır ve engellemez. Eşzamansız kodu sıralı hale getirmek için
suspend
işlevlerini kullanır. - Bir coroutine,
suspend
ile işaretlenmiş bir işlevi çağırdığında normal bir işlev çağrısı gibi işlev döndürülene kadar engellemek yerine sonuç hazır olana kadar yürütmeyi askıya alır. Ardından, sonuçla birlikte kaldığı yerden devam eder. - Engelleme ve askıya alma arasındaki fark, bir ileti dizisi engellendiğinde başka hiçbir işlemin yapılmamasıdır. İş parçacığı askıya alınırsa sonuç kullanılabilir hale gelene kadar diğer işlemler devam eder.
Bir coroutine'i başlatmak için iş, dağıtıcı ve kapsam gerekir:
- Temel olarak iş, iptal edilebilen her şeydir. Her eş yordamın bir işi vardır ve eş yordamı iptal etmek için işi kullanabilirsiniz.
- Dispatcher, çeşitli iş parçacıklarında çalışacak eş yordamlar gönderir.
Dispatcher.Main
, görevleri ana iş parçacığında çalıştırır veDispartcher.IO
, engelleme G/Ç görevlerini ortak bir iş parçacığı havuzuna boşaltmak için kullanılır. - Kapsam, eş yordamın çalışacağı bağlamı tanımlamak için iş ve dağıtıcı gibi bilgileri birleştirir. Kapsamlar, eşzamanlı rutinleri takip eder.
Veritabanı işlemlerini tetikleyen tıklama işleyicilerini uygulamak için şu kalıbı kullanın:
- Sonuç kullanıcı arayüzünü etkilediği için ana veya kullanıcı arayüzü iş parçacığında çalışan bir coroutine başlatın.
- Uzun süren işi yapmak için bir askıya alma işlevi çağırın. Böylece sonucu beklerken kullanıcı arayüzü iş parçacığını engellemezsiniz.
- Uzun süren çalışmanın kullanıcı arayüzüyle ilgisi yoktur. Bu nedenle, G/Ç bağlamına geçin. Bu sayede, işlemler bu tür operasyonlar için optimize edilmiş ve ayrılmış bir iş parçacığı havuzunda çalışabilir.
- Ardından, işi yapmak için veritabanı işlevini çağırın.
Nesne her değiştiğinde Transformations
nesnesinden dize oluşturmak için LiveData
haritasını kullanın.
Udacity kursu:
Android Geliştirici Dokümanları:
RoomDatabase
- <include/> ile düzenleri yeniden kullanma
ViewModelProvider.Factory
SimpleDateFormat
HtmlCompat
Diğer belgeler ve makaleler:
- Fabrika deseni
- Eş yordamlar codelab'i
- Coroutines, resmi belgeler
- Coroutine bağlamı ve dağıtıcılar
Dispatchers
- Android'in hız sınırını aşma
Job
launch
- Kotlin'de dönüşler ve atlamalar
- CDATA, karakter verileri anlamına gelir. CDATA, bu dizeler arasındaki verilerin XML işaretlemesi olarak yorumlanabilecek veriler içerdiği ancak bu şekilde yorumlanmaması gerektiği anlamına gelir.
Bu bölümde, bir eğitmenin yönettiği kurs kapsamında bu codelab'i tamamlayan öğrenciler için olası ödevler listelenmektedir. Eğitmen, aşağıdakileri yapmalıdır:
- Gerekirse ödev atayın.
- Öğrencilere ev ödevi ödevlerini nasıl göndereceklerini bildirin.
- Ödevlere not verin.
Eğitmenler bu önerileri istedikleri kadar kullanabilir ve uygun olduğunu düşündükleri diğer ödevleri verebilirler.
Bu codelab'i kendi başınıza tamamlıyorsanız bilginizi test etmek için bu ödevleri kullanabilirsiniz.
Bu soruları yanıtlayın.
1. Soru
Aşağıdakilerden hangileri eş yordamların avantajlarıdır?
- Engellemeyen sorunlar
- Eşzamansız olarak çalışırlar.
- Ana iş parçacığı dışında bir iş parçacığında çalıştırılabilirler.
- Uygulamaların her zaman daha hızlı çalışmasını sağlar.
- İstisnaları kullanabilir.
- Bunlar doğrusal kod olarak yazılabilir ve okunabilir.
2. Soru
Askıya alma işlevi nedir?
suspend
anahtar kelimesiyle açıklama eklenmiş normal bir işlev.- Coroutine'ler içinde çağrılabilen bir işlev.
- Bir askıya alma işlevi çalışırken çağırma iş parçacığı askıya alınır.
- Askıya alma işlevleri her zaman arka planda çalışmalıdır.
3. Soru
Bir ileti dizisini engelleme ve askıya alma arasındaki fark nedir? Doğru olanların tümünü işaretleyin.
- Yürütme engellendiğinde, engellenen ileti dizisinde başka hiçbir işlem yürütülemez.
- Yürütme askıya alındığında, iş parçacığı, boşaltılan işin tamamlanmasını beklerken başka işler yapabilir.
- İş parçacıkları bekliyor veya hiçbir şey yapmıyor olabileceğinden askıya alma işlemi daha verimlidir.
- Yürütme, engellenmiş veya askıya alınmış olsa da devam etmeden önce eş yordamın sonucunu beklemeye devam eder.
Bir sonraki derse geçin:
Bu kurstaki diğer codelab'lerin bağlantılarını Android Kotlin Hakkında Temel Bilgiler codelab'leri açılış sayfasında bulabilirsiniz.