Android Kotlin Hakkında Temel Bilgiler 06.2: Coroutines ve Room

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

  1. GitHub'dan TrackMySleepQuality-Coroutines-Starter uygulamasını indirin.
  2. 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.

  1. 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çin merge 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.
  2. navigation klasöründe navigation.xml dosyasını açın. İki parça ve bunları birbirine bağlayan gezinme işlemlerini görebilirsiniz.
  3. 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

  1. sleeptracker paketinde SleepTrackerViewModel.kt dosyasını açın.
  2. Başlangıç uygulamasında sizin için sağlanan ve aşağıda da gösterilen SleepTrackerViewModel sınıfını inceleyin. Dersin AndroidViewModel() 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

  1. sleeptracker paketinde SleepTrackerViewModelFactory.kt dosyasını açın.
  2. 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 ve ViewModelProvider.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üren create() 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

  1. 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ğer null ise IllegalArgumentException oluşturur.
val application = requireNotNull(this.activity).application
  1. DAO'ya yapılan bir referans aracılığıyla veri kaynağınıza referans vermeniz gerekir. onCreateView() içinde, return öğesinden önce bir dataSource tanımlayın. Veritabanının DAO'sunu referans almak için SleepDatabase.getInstance(application).sleepDatabaseDao kullanın.
val dataSource = SleepDatabase.getInstance(application).sleepDatabaseDao
  1. onCreateView() içinde, return öğesinden önce viewModelFactory öğesinin bir örneğini oluşturun. dataSource ve application sınavlarını geçmeniz gerekir.
val viewModelFactory = SleepTrackerViewModelFactory(dataSource, application)
  1. 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)
  1. 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:

  1. <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:

  1. 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)
  1. sleepTrackerViewModel bağlama değişkenini sleepTrackerViewModel öğesine atayın. Bu kodu onCreateView() içine, SleepTrackerViewModel öğesini oluşturan kodun altına yerleştirin:
binding.sleepTrackerViewModel = sleepTrackerViewModel
  1. 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.
  2. 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.

  1. 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, proje build.gradle dosyasında coroutine_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"
  1. SleepTrackerViewModel dosyasını açın.
  2. Sınıfın gövdesinde viewModelJob öğesini tanımlayın ve Job öğesinin bir örneğini atayın. Bu viewModelJob, 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()
  1. 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ğinde onCleared() çağrılır.
override fun onCleared() {
   super.onCleared()
   viewModelJob.cancel()
}
  1. viewModelJob tanımının hemen altında, coroutine'ler için bir uiScope 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çin CoroutineScope ö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)
  1. uiScope tanımının altında, mevcut geceyi tutmak için tonight adlı bir değişken tanımlayın. Verileri gözlemleyip değiştirebilmeniz gerektiğinden değişkeni MutableLiveData yapın.
private var tonight = MutableLiveData<SleepNight?>()
  1. tonight değişkenini mümkün olan en kısa sürede başlatmak için tonight tanımının altında bir init bloğu oluşturun ve initializeTonight() işlevini çağırın. initializeTonight() değerini sonraki adımda tanımlarsınız.
init {
   initializeTonight()
}
  1. init bloğunun altına initializeTonight() kodunu uygulayın. uiScope içinde bir eş yordam başlatın. İçeride, tonight için değeri getTonightFromDatabase() çağırarak veritabanından alın ve değeri tonight.value'ye atayın. getTonightFromDatabase() değerini sonraki adımda tanımlarsınız.
private fun initializeTonight() {
   uiScope.launch {
       tonight.value = getTonightFromDatabase()
   }
}
  1. getTonightFromDatabase()'yi uygulama. Mevcut bir SleepNight başlatılmamışsa bunu boş değer atanabilir bir SleepNight döndüren private 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? { }
  1. 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) {}
  1. 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.

  1. onStartTracking() için işlev tanımıyla başlayın. Tıklama işleyicilerini onCleared() öğesinin üstüne SleepTrackerViewModel dosyasına yerleştirebilirsiniz.
fun onStartTracking() {}
  1. onStartTracking() içinde, devam etmek ve kullanıcı arayüzünü güncellemek için bu sonuca ihtiyacınız olduğundan uiScope içinde bir eş yordam başlatın.
uiScope.launch {}
  1. Coroutine başlatma işlemi içinde, geçerli zamanı başlangıç zamanı olarak yakalayan yeni bir SleepNight oluşturun.
        val newNight = SleepNight()
  1. Coroutine başlatma işlemi içindeyken insert() işlevini çağırarak veritabanına newNight ekleyin. Bu insert() 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)
  1. Ayrıca, coroutine başlatma işlemi içinde tonight değerini güncelleyin.
       tonight.value = getTonightFromDatabase()
  1. onStartTracking()'nın altında, insert() işlevini bağımsız değişken olarak SleepNight alan bir private suspend işlevi olarak tanımlayın.
private suspend fun insert(night: SleepNight) {}
  1. insert() gövdesi için I/O bağlamında bir eşzamanlı rutin başlatın ve DAO'dan insert() çağırarak geceyi veritabanına ekleyin.
   withContext(Dispatchers.IO) {
       database.insert(night)
   }
  1. fragment_sleep_tracker.xml düzen dosyasında, daha önce ayarladığınız veri bağlama özelliğini kullanarak onStartTracking() için tıklama işleyicisini start_button öğesine ekleyin. @{() -> işlev gösterimi, bağımsız değişken almayan ve sleepTrackerViewModel içindeki tıklama işleyicisini çağıran bir lambda işlevi oluşturur.
android:onClick="@{() -> sleepTrackerViewModel.onStartTracking()}"
  1. 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.

  1. Util.kt dosyasını açın ve formatNights() ile ilişkili import 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 ve Cmd+/ veya Control+/ tuşuna basın.
  2. formatNights() işlevinin, HTML biçimlendirmeli bir dize olan Spanned türünü döndürdüğünü unutmayın.
  3. 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.
  4. SleepTrackerViewModel'i açın. SleepTrackerViewModel sınıfında, uiScope tanımının altında nights adlı bir değişken tanımlayın. Veritabanındaki tüm geceleri alıp nights değişkenine atayın.
private val nights = database.getAllNights()
  1. nights tanımının hemen altına, nights öğesini nightsString öğesine dönüştürecek kodu ekleyin. Util.kt sınıfındaki formatNights() işlevini kullanın.

    nights öğesini Transformations sınıfındaki map() işlevine iletin. Dize kaynaklarınıza erişmek için eşleme işlevini formatNights() olarak tanımlayın. nights ve Resources nesnesi sağlayın.
val nightsString = Transformations.map(nights) { nights ->
   formatNights(nights, application.resources)
}
  1. fragment_sleep_tracker.xml düzen dosyasını açın. TextView içinde, android:text özelliğinde kaynak dizesini artık nightsString referansıyla değiştirebilirsiniz.
"@{sleepTrackerViewModel.nightsString}"
  1. Kodunuzu yeniden oluşturun ve uygulamayı çalıştırın. Başlangıç zamanlarıyla birlikte tüm uyku verileriniz artık gösterilmelidir.
  2. 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.

  1. onStopTracking() öğesini ViewModel listesine ekleyin. uiScope içinde bir coroutine başlatın. Bitiş zamanı henüz ayarlanmadıysa endTimeMilli değerini mevcut sistem zamanına ayarlayın ve gece verileriyle update() işlevini çağırın.

    Kotlin'de return@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)
   }
}
  1. 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)
   }
}
  1. 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şleyicisini stop_button öğesine ekleyin.
android:onClick="@{() -> sleepTrackerViewModel.onStopTracking()}"
  1. Uygulamanızı derleyip çalıştırın.
  2. 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

  1. Benzer şekilde, onClear() ve clear() işaretlemelerini uygulayın.
fun onClear() {
   uiScope.launch {
       clear()
       tonight.value = null
   }
}

suspend fun clear() {
   withContext(Dispatchers.IO) {
       database.clear()
   }
}
  1. Tıklama işleyicisini kullanıcı arayüzüne bağlamak için fragment_sleep_tracker.xml öğesini açın ve tıklama işleyicisini clear_button öğesine ekleyin.
android:onClick="@{() -> sleepTrackerViewModel.onClear()}"
  1. Uygulamanızı derleyip çalıştırın.
  2. 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 , 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 ve Dispartcher.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:

  1. 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.
  2. 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.
  3. 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.
  4. 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ı:

Diğer belgeler ve makaleler:

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: 6.3 Düğme durumlarını kontrol etmek için LiveData'yı kullanma

Bu kurstaki diğer codelab'lerin bağlantılarını Android Kotlin Hakkında Temel Bilgiler codelab'leri açılış sayfasında bulabilirsiniz.