Android Kotlin Fundamentals 06.2: Korintinler ve Oda

Bu codelab, Android Kotlin Temelleri kursuna dahildir. Codelab'ler üzerinden sırayla çalışıyorsanız bu kurstan en iyi şekilde yararlanabilirsiniz. Tüm kurs codelab'leri Android Kotlin Fundamentals codelabs açılış sayfasında listelenmektedir.

Giriş

Uygulamanız için sorunsuz bir kullanıcı deneyimi oluşturmanın en önemli önceliklerinden biri, kullanıcı arayüzünün her zaman duyarlı ve sorunsuz çalıştığından emin olmaktır. Kullanıcı arayüzü performansını iyileştirmenin bir yolu, veritabanı işlemleri gibi uzun süreli görevleri arka plana taşımaktır.

Bu codelab'de, veritabanı iletimini ana iş parçacığının dışında gerçekleştirmek için Kotlin eş yordamlarını kullanarak TrackMySleepquality uygulamasının kullanıcıya yönelik kısmını uyguluyorsunuz.

Bilmeniz gerekenler

Aşağıdaki konular hakkında bilgi sahibi olmalısınız:

  • Bir etkinlik, parçalar, görünümler ve tıklama işleyiciler kullanarak temel bir kullanıcı arayüzü (UI) oluşturma.
  • Parçalar arasında gezinme ve parçalar arasında basit verileri iletmek için safeArgs kullanma.
  • Modelleri görüntüleyin, model fabrikalarını, dönüşümleri ve LiveData'i görüntüleyin.
  • Room veritabanı oluşturma, DAO oluşturma ve varlıkları tanımlama.
  • Mesaj dizisi oluşturma ve çoklu işleme kavramları hakkında bilgi sahibiyseniz bu yöntem yararlıdır.

Neler öğreneceksiniz?

  • Android'de ileti dizilerinin işleyiş şekli.
  • Veritabanı işlemlerini ana iş parçacığının dışına taşımak için Kotlin eş yordamlarını kullanma.
  • Biçimlendirilmiş veriler TextView içinde nasıl görüntülenir?

Yapacaklarınız

  • Veritabanındaki verileri toplamak, depolamak ve görüntülemek için TrackMySleepquality uygulamasını genişletin.
  • Uzun süreli veritabanı işlemlerini arka planda çalıştırmak için eş yordam kullanın.
  • Gezinmeyi ve atıştırmalık çubuğunun görüntülenmesini tetiklemek için LiveData politikasını kullanın.
  • Düğmeleri etkinleştirmek ve devre dışı bırakmak için LiveData öğesini kullanın.

Bu codelab'de, TrackMySleepquality uygulamasının görünüm modelini, eş yordamlarını ve veri görüntüleme bölümlerini oluşturursunuz.

Uygulamada, aşağıdaki resimde gösterildiği gibi parçalarla temsil edilen iki ekran vardır.

Solda gösterilen ilk ekranda izlemeyi başlatmak ve durdurmak için düğmeler 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ğ tarafta gösterilen ikinci ekran uyku kalitesi puanı seçmek içindir. Uygulamada, puan sayısal olarak gösterilir. Uygulama, geliştirme amacıyla hem yüz simgelerini hem de sayısal eşdeğerlerini gösterir.

Kullanıcının akışı şu şekildedir:

  • Kullanıcı uygulamayı açar ve uyku izleme ekranı sunulur.
  • Kullanıcı Başlat düğmesine dokunur. Bu işlem, başlangıç zamanını kaydeder ve gösterir. Başlat düğmesi devre dışıdır ve Durdur düğmesi etkindir.
  • Kullanıcı Durdur düğmesine dokunur. Bu işlem, bitiş zamanını kaydeder ve uyku kalitesi ekranını açar.
  • Kullanıcı bir uyku kalitesi simgesi seçer. Ekran kapanır ve izleme ekranında uyku bitiş zamanı ve uyku kalitesi görüntülenir. Durdur düğmesi devre dışıdır ve Başlat düğmesi etkindir. Uygulama başka bir gece için 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üş olmaksızın silinir. "Emin misiniz?" diye bir mesaj yoktur.

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 öğelerini görüntüleyin
  • Oda veritabanı

Bu görevde biçimlendirilmiş uyku izleme verilerini görüntülemek için bir TextView kullanırsınız. (Son arayüz bu değildir. Başka bir codelab'de daha iyi bir yöntem öğreneceksiniz.)

Önceki codelab'de oluşturduğunuz TrackMySleepquality uygulamasıyla devam edebilir veya bu codelab için başlangıç uygulamasını indirebilirsiniz.

1. Adım: Başlangıç uygulamasını indirin ve ç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ının kullanıcı arayüzünü gösteriyor ancak veri yok. Düğmeler, dokunmaya yanıt vermez.

2. Adım: Kodu inceleyin

Bu codelab'in başlangıç kodu, 6.1 Oda veritabanı kod laboratuvarının çözüm kodu ile aynıdır.

  1. res/layout/activity_main.xml dosyasını açın. Bu düzende nav_host_fragment parçası bulunur. Ayrıca <merge> etiketine dikkat edin.

    merge etiketi, düzenleri eklerken gereksiz düzenleri ortadan kaldırmak için kullanılabilir. Bu etiketin kullanılması iyi bir fikirdir. Gereksiz düzene örnek olarak ConstraintLayout > LinearLayout > TextView verilebilir. Bu durumda sistem, Doğrusal Düzen'i ortadan kaldırabilir. Bu tür optimizasyonlar, görüntüleme hiyerarşisini basitleştirebilir ve uygulama performansını iyileştirebilir.
  2. Gezinme klasöründe navigasyon.xml sayfasını açın. İki parça ve bunları bağlayan gezinme işlemleri görebilirsiniz.
  3. Düzen klasöründe, XML düzenini görmek için uyku izleyici parçasını çift tıklayın. Aşağıdakilere dikkat edin:
  • Düzen verileri, veri bağlamayı etkinleştirmek için bir <layout> öğesine sarmalanır.
  • ConstraintLayout ve diğer görünümler <layout> öğesinin içinde düzenlenir.
  • Dosyada bir yer tutucu <data> etiketi vardır.

Başlangıç uygulaması, kullanıcı arayüzü için boyutlar, renkler ve stil de sağlar. Uygulama; Room veritabanı, DAO ve SleepNight varlığı içeriyor. Önceki codelab'i tamamlamadıysanız kodun bu yönlerini kendiniz araştırdığınızdan emin olun.

Artık veritabanınız ve kullanıcı arayüzünüz olduğuna göre veri toplamanız, verileri veritabanına eklemeniz ve verileri göstermeniz gerekir. Tüm bu işlemler görünüm modelinde yapılır. Uyku izleyici görüntüleme modeliniz, düğme tıklamalarını işleme alır, DAO üzerinden veritabanıyla etkileşime geçer ve LiveData üzerinden kullanıcı arayüzüne veri sağlar. Tüm veritabanı işlemlerinin ana kullanıcı arayüzü ileti dizisinden çalıştırılması ve bu işlemi eş yordamlar kullanarak gerçekleştirmeniz gerekir.

1. Adım: SleepTrackerViewModel ekleyin

  1. sleeptracker paketinde SleepTrackerViewModel.kt'yi açın.
  2. Hem başlangıç uygulamasında size sunulan hem de aşağıda gösterilen SleepTrackerViewModel sınıfını inceleyin. Dersin AndroidViewModel() tarihinde sona ereceğini unutmayın. Bu sınıf, ViewModel ile aynıdır ancak uygulama bağlamını parametre olarak alır ve mülk olarak kullanılabilir hale getirir. Buna daha sonra ihtiyacınız olacaktır.
class SleepTrackerViewModel(
       val database: SleepDatabaseDao,
       application: Application) : AndroidViewModel(application) {
}

2. Adım: SleepTrackerViewModelFactory ekleyin

  1. sleeptracker paketinde SleepTrackerViewModelFactory.kt'yi açın.
  2. Fabrika için sizin için sağlanan kodu aşağıda görebilirsiniz:
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:

  • Sağlanan SleepTrackerViewModelFactory, ViewModel ile aynı bağımsız değişkeni alır ve ViewModelProvider.Factory kapsamını genişletir.
  • Fabrika içinde kod, create() öğesini geçersiz kılar. Bu, tüm sınıf türlerini bağımsız değişken olarak alır ve ViewModel döndürür.
  • Kod, create() gövdesinde mevcut bir SleepTrackerViewModel sınıfının olup olmadığını kontrol eder. Böyle bir etkinlik varsa sınıfının bir örneğini döndürür. Aksi halde, kod bir istisna oluşturur.

3. Adım: SleepTrackerFragment'u güncelleyin

  1. SleepTrackerFragment içinde uygulama bağlamına dair bir referans alın. Referansı onCreateView() alanına, binding değerinin altına yerleştirin. Görüntü modeli fabrika sağlayıcısına iletmek için bu parçanın bağlı olduğu uygulamaya referans vermeniz gerekir.

    Değer null ise requireNotNull Kotlin işlevi IllegalArgumentException değerini döndürür.
val application = requireNotNull(this.activity).application
  1. DAO referansı aracılığıyla veri kaynağınıza referans vermeniz gerekir. onCreateView() içinde return öncesinde bir dataSource tanımlayın. Veritabanının DAO'suna referans almak için SleepDatabase.getInstance(application).sleepDatabaseDao kullanın.
val dataSource = SleepDatabase.getInstance(application).sleepDatabaseDao
  1. onCreateView() içinde return öncesinde viewModelFactory öğesinin bir örneğini oluşturun. Değerlendirmeyi dataSource ve application geçmeniz gerekir.
val viewModelFactory = SleepTrackerViewModelFactory(dataSource, application)
  1. Fabrikanız hazır olduğuna göre SleepTrackerViewModel uygulamasına başvurabilirsiniz. SleepTrackerViewModel::class.java parametresi, bu nesnenin çalışma zamanı Java sınıfını belirtir.
val sleepTrackerViewModel =
       ViewModelProviders.of(
               this, viewModelFactory).get(SleepTrackerViewModel::class.java)
  1. Bitmiş 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 kadar onCreateView() yöntemi kullanıldı:

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 yönergesini ayarladığınızda ViewModel öğesini kullanıcı arayüzüne bağlamak için SleepTrackerFragment ürününde veri bağlamayı ayarlama işlemini tamamlamanız gerekir.


fragment_sleep_tracker.xml düzen dosyasında:

  1. <data> blokunun 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. Geçerli etkinliği, bağlamanın yaşam döngüsü sahibi olarak ayarlayın. Bu kodu onCreateView() yönteminin içine, return ifadesinden önce ekleyin:
binding.setLifecycleOwner(this)
  1. sleepTrackerViewModel bağlama değişkenini sleepTrackerViewModel değerine atayın. Bu kodu, onCreateView() içinde, SleepTrackerViewModel etiketinin oluşturulduğu kodun altına yerleştirin:
binding.sleepTrackerViewModel = sleepTrackerViewModel
  1. Bağlama nesnesini yeniden oluşturmanız gerekeceğinden muhtemelen bir hata görürsünüz. Hatadan kurtulmak için projeyi temizleyip yeniden oluşturun.
  2. Son olarak, her zaman olduğu gibi, kodunuzun hatasız bir şekilde oluşturulduğundan ve çalıştığından emin olun.

Kotlinler uzun süreli işleri zarif ve verimli bir şekilde başarmanın en iyi yoludur. Kotlin eş yordamları, geri çağırmaya dayalı kodu sıralı koda dönüştürmenizi sağlar. Sıralı olarak yazılan kodlar genelde daha kolay okunur ve hatta istisnalar gibi dil özellikleri kullanılabilir. En sonunda, eş yordamlar ve geri çağırmalar aynı işlemi yapar: Uzun süreli bir görevden bir sonuç elde edilene kadar bekler ve yürütmeye devam ederler.

Coroutine'ler aşağıdaki özelliklere sahiptir:

  • Korintinler eşzamansızdur ve engelleyici değildir.
  • Zaman damgaları, eşzamansız kodu sıralı hale getirmek için askıya alma işlevlerini kullanır.

Soroutin'ler eşzamansızdır.

Korintin, programınızın ana yürütme adımlarından bağımsız olarak çalışır. Bu, paralel veya ayrı bir işleyen üzerinde olabilir. Ayrıca, uygulamanın geri kalanı giriş beklerken biraz işleme koyulabilirsiniz. Eş zamansızlığın önemli yanlarından biri, net bir şekilde bekleyene kadar sonucun beklenmemesidir.

Örneğin, araştırma gerektiren bir sorunuz olduğunu ve bir iş arkadaşınızdan cevabı bulmasını istediğinizi varsayalım. Çalışıyorlar ve çalışıyorlar. Sanki bu işi ayrı ayrı ileti dizisinde yapıyorlar ve ayrı bir iş parçacığında çalışıyorlar. İş arkadaşınız geri gelip cevabın ne olduğunu söyleyene kadar yanıta bağlı olmayan başka çalışmalar yapmaya devam edebilirsiniz.

Sitede bloke edici öğeler yok.

Engellemeyen, bir coroutine'in ana veya kullanıcı arayüzü iş parçacığını engellemediği anlamına gelir. Bu nedenle, coroutine'ler için kullanıcı arayüzü etkileşimi her zaman öncelikli olduğundan kullanıcılar her zaman mümkün olduğunca sorunsuz bir deneyim yaşar.

Coroutine'lar, eşzamansız kodu sıralı hale getirmek için askıya alma işlevlerini kullanır.

Anahtar kelime suspend, Kotlin® tarafından bir işlevi veya işlev türünü eş yordamlar için kullanılabilecek şekilde işaretleme yöntemidir. Coroutine, suspend ile işaretlenmiş bir işlevi çağırdığında, işlev normal bir işlev çağrısı gibi döndürülene kadar engellemek yerine sonuç hazır olana kadar eş yordam yürütmeyi askıya alır. Ardından eş yordam, kaldığı yerden devam eder.

Korint askıya alınmış ve bir sonucu bekliyorken, üzerinde çalıştığı ileti dizisinin engellemesini kaldırır. Bu şekilde, diğer işlevler veya eş yordamlar çalışabilir.

suspend anahtar kelimesi, kodun çalıştığı ileti dizisini belirtmez. Askıya alma işlevi bir arka plan ileti dizisinde veya ana ileti dizisinde çalışabilir.

Kotlin kullanmak için üç şeye ihtiyacınız vardır:

  • İş
  • Sevk görevlisi
  • Kapsam

İş: Temel olarak, bir iş iptal edilebilir olan herhangi bir şeydir. Her coroutine'in bir işi vardır ve coroutine'i iptal etmek için bu işi kullanabilirsiniz. İşler, üst-alt hiyerarşileri halinde düzenlenebilir. Bir üst işin iptal edilmesi, işin tüm alt işçilerini hemen iptal eder. Bu, her bir eş yordamı manuel olarak iptal etmekten çok daha kolaydır.

Gönderim görevlisi: Kariyer, çeşitli ileti dizilerinde çalışacak coroutine'ler gönderir. Örneğin, Dispatcher.Main görevleri ana ileti dizisinde çalıştırır ve Dispatcher.IO, paylaşılan G/Ç görevlerini paylaşılan bir ileti dizisi havuzuna boşaltır.

Kapsam: coroutine® scope, eş yordamın çalıştırıldığı bağlamı tanımlar. Kapsam, bir eş yordam işi ve görev dağıtıcıyla ilgili bilgileri birleştirir. Kapsamlar, eş yordamları takip eder. Bir eş yordamı başlattığınızda, kapsam dahilinde olan coroutine'i hangi kapsamın takip edeceğini belirttiğiniz anlamına gelir.

Kullanıcının uyku verileriyle aşağıdaki şekillerde etkileşimde bulunabilmesini istersiniz:

  • Kullanıcı, Başlat düğmesine dokunduğunda uygulama, yeni bir uyku gecesi oluşturur ve uyku gecesini veritabanında depolar.
  • Kullanıcı Durdur düğmesine dokunduğunda uygulama, geceyi bir bitiş zamanı ile günceller.
  • Kullanıcı Temizle düğmesine dokunduğunda uygulama, veritabanındaki verileri siler.

Bu veritabanı işlemleri uzun sürebilir, dolayısıyla ayrı bir ileti dizisinde çalıştırılmalıdır.

1. Adım: Veritabanı işlemleri için eş yordamlar oluşturun

Uyku İzleyici uygulamasında Başlat düğmesine dokunulduğunda, SleepTrackerViewModel içinde yeni bir SleepNight örneği oluşturmak ve bu örneği veritabanında depolamak için bir işlev çağırmak istersiniz.

Düğmelerden herhangi birine dokunduğunuzda, SleepNight oluşturma veya güncelleme gibi bir veritabanı işlemi tetiklenir. Bu nedenle ve diğer uygulamalarda, uygulama düğmeleri için tıklama işleyiciler uygulamak üzere eş yordamlar kullanırsınız.

  1. Uygulama düzeyinde build.gradle dosyasını açın ve eş yordamların bağımlılıklarını bulun. Coroutine'leri kullanmak için sizin için eklenen bu bağımlılara ihtiyacınız vardır.

    $coroutine_version, build.gradle projesi 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 ona bir Job örneği 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ş yordamları iptal etmenize olanak tanır. Bu şekilde, geri dönmeleri gereken bir yordam yakalanmazsınız.
private var viewModelJob = Job()
  1. Sınıfın sonunda onCleared() öğesini geçersiz kılın ve tüm eş yordamları iptal edin. ViewModel yıkıldığında onCleared() çağrılır.
override fun onCleared() {
   super.onCleared()
   viewModelJob.cancel()
}
  1. viewModelJob ifadesinin tanımının hemen altında, coroutine'ler için bir uiScope tanımlayın. Kapsam, eş zamanlı olarak hangi iş parçacığının çalıştırılacağını belirler ve kapsamın iş hakkında da bilgi sahibi olması gerekir. Kapsam almak için bir CoroutineScope örneği isteyin ve bir görevliye ve bir işe geçin.

Dispatchers.Main kullanımı, uiScope ürününde başlatılan eş yordamların ana iş parçacığında çalıştırılacağı anlamına gelir. ViewModel tarafından başlatılan çoğu eş yordam için bu makul bir durumdur. Çünkü bu eş yordamlar işlendikten sonra kullanıcı arayüzünde bir güncelleme gerçekleşir.

private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)
  1. uiScope tanımının altında, geceyi yerleştirmek için tonight adında bir değişken tanımlayın. Verileri gözlemleyip değiştirebilmeniz gerektiğinden değişken MutableLiveData olmalıdır.
private var tonight = MutableLiveData<SleepNight?>()
  1. tonight değişkenini en kısa sürede başlatmak için tonight tanımının altında bir init bloku oluşturun ve initializeTonight() çağrısı yapın. initializeTonight() öğesini bir sonraki adımda tanımlıyorsunuz.
init {
   initializeTonight()
}
  1. init blokunun altında initializeTonight() özelliğini uygulayın. uiScope bölgesinde bir eş yordam başlatın. İçeride, getTonightFromDatabase() çağrısı yaparak veritabanındaki tonight değerini alın ve tonight.value hedefine atayın. getTonightFromDatabase() öğesini bir sonraki adımda tanımlıyorsunuz.
private fun initializeTonight() {
   uiScope.launch {
       tonight.value = getTonightFromDatabase()
   }
}
  1. getTonightFromDatabase()'yi uygulama. Başlatılmış SleepNight değeri yoksa boş bir SleepNight döndüren bir private suspend işlevi olarak tanımlayın. İşlevin bir şey döndürmesi gerektiğinden bu bir hata oluşturur.
private suspend fun getTonightFromDatabase(): SleepNight? { }
  1. getTonightFromDatabase() fonksiyonunun gövdesinde, Dispatchers.IO bağlamında çalışan bir eş yordamdan sonucu döndürün. Veritabanından veri almak G/Ç işlemi olduğundan ve kullanıcı arayüzüyle herhangi bir ilgisi olmadığından G/Ç dağıtıcısını kullanın.
  return withContext(Dispatchers.IO) {}
  1. İade blokunun içinde, koridorun bu gece (en yeni gece) veritabanından çıkmasına izin verin. Başlangıç ve bitiş zamanları aynı değilse (gece zaten tamamlandıysa) null değerini döndürün. Aksi takdirde geceyi iade edin.
       var night = database.getTonight()
       if (night?.endTimeMilli != night?.startTimeMilli) {
           night = null
       }
       night

Tamamladığınız getTonightFromDatabase() askıya alma işlevi aşağıdaki gibi görünecektir. 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şleyici ekleyin

Artık Başlat düğmesi için tıklama işleyici olan onStartTracking()'yi uygulayabilirsiniz. Yeni bir SleepNight oluşturmanız, bunu veritabanına eklemeniz ve tonight adlı kullanıcıya atamanız gerekir. onStartTracking() yapısı initializeTonight() yapısına benzeyecektir.

  1. onStartTracking() için işlev tanımıyla başlayın. SleepTrackerViewModel dosyasına tıklama işleyicilerini onCleared() üzerine yerleştirebilirsiniz.
fun onStartTracking() {}
  1. Devam etmek ve kullanıcı arayüzünü güncellemek için bu sonuca ihtiyacınız olduğundan onStartTracking() içinde uiScope içinde bir eş yordam başlatın.
uiScope.launch {}
  1. Coroutine lansmanında yeni bir SleepNight oluşturun. Bu zaman, başlangıç zamanını belirtir.
        val newNight = SleepNight()
  1. Coroutine lansmanındayken newNight veritabanını eklemek için insert() numaralı telefonu arayın. Bu insert() askıya alma işlevini henüz tanımlamadığınız için bir hata mesajı göreceksiniz. (Bu, aynı addaki DAO işlevi değildir.)
       insert(newNight)
  1. Ayrıca eş yordam lansmanında, tonight uygulamasını güncelleyin.
       tonight.value = getTonightFromDatabase()
  1. onStartTracking() değerinin altında, insert() öğesini bağımsız değişkeni olarak SleepNight ifadesini alan private suspend işlevi olarak tanımlayın.
private suspend fun insert(night: SleepNight) {}
  1. insert() gövdesinde, G/Ç bağlamında bir eş yordam başlatın ve DAO'dan insert() işlevini çağırarak veritabanına geceyi ekleyin.
   withContext(Dispatchers.IO) {
       database.insert(night)
   }
  1. fragment_sleep_tracker.xml düzen dosyasında, daha önce ayarladığınız veri bağlama büyüsünü kullanarak onStartTracking() için tıklama işleyiciyi start_button öğesine ekleyin. @{() -> işlevi gösterimi, bağımsız değişken içermeyen ve sleepTrackerViewModel içinde tıklama işleyicisini çağıran bir lambda işlevi oluşturur.
android:onClick="@{() -> sleepTrackerViewModel.onStartTracking()}"
  1. Uygulamanızı oluşturup çalıştırın. Başlat düğmesine dokunun. Bu işlemle veri oluşturulur, ancak henüz hiçbir şey göremezsiniz. Bu sorunu sonra da düzeltirsiniz.
fun someWorkNeedsToBeDone {
   uiScope.launch {

        suspendFunction()

   }
}

suspend fun suspendFunction() {
   withContext(Dispatchers.IO) {
       longrunningWork()
   }
}

3. Adım: Verileri görüntüleyin

SleepTrackerViewModel, DAO'da getAllNights() LiveData döndürdüğü için nights değişkeni LiveData öğesine referans veriyor.

Veritabanındaki veriler her değiştiğinde LiveData nights en son verileri gösterecek şekilde güncellenir. Hiçbir zaman LiveData özelliğini açıkça ayarlamanız veya güncellemeniz gerekmez. Room, verileri veritabanıyla eşleşecek şekilde günceller.

Ancak, bir metin görünümünde nights görüntülerseniz nesne referansı gösterilir. Nesnenin içeriğini görmek için verileri biçimlendirilmiş bir dizeye dönüştürün. nights, veritabanından yeni veriler aldığında yürütülen Transformation eşlemesini kullanır.

  1. Util.kt dosyasını açıp formatNights() öğesinin tanımı ve ilişkili import ifadelerinin açıklamasını kaldırın. Android Studio'da kodun açıklamasını kaldırmak için // ile işaretlenen tüm kodu seçin ve Cmd+/ veya Control+/ tuşlarına basın.
  2. formatNights() öğesinin, HTML biçimli bir dize olan Spanned türünü döndürdüğüne dikkat edin.
  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ından tüm geceleri alın ve bunları nights değişkenine atayın.
private val nights = database.getAllNights()
  1. nights öğesinin tanımının hemen altına, nights kodunu nightsString biçimine dönüştürmek için gerekli kodu ekleyin. Util.kt öğesindeki formatNights() işlevini kullanın.

    Transformations sınıfından map() işlevine nights değerini iletin. Dize kaynaklarınıza erişim elde etmek için eşleme işlevini formatNights() çağrısı olarak tanımlayın. nights ve bir 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 ürünündeki android:text özelliğinde artık kaynak dizeyi nightsString referansıyla değiştirebilirsiniz.
"@{sleepTrackerViewModel.nightsString}"
  1. Kodunuzu yeniden oluşturup uygulamayı çalıştırın. Başlangıç zamanına sahip tüm uyku verileriniz şimdi görünmelidir.
  2. Başlat düğmesine birkaç kez daha dokunursanız daha fazla veri görürsünüz.

Sonraki adımda Durdur düğmesi için işlevleri etkinleştirin.

4. Adım: Durdur düğmesi için tıklama işleyici ekleyin

Önceki adımla aynı kalıbı kullanarak, SleepTrackerViewModel. içinde Durdur düğmesi için tıklama işleyiciyi uygulayın

  1. ViewModel ödeme listesine onStopTracking() ekleyin. uiScope uygulamasında bir eş yordam başlatın. Bitiş zamanı henüz belirlenmediyse endTimeMilli öğesini geçerli sistem zamanına ayarlayın ve gece verileriyle update() öğesini çağırın.

    Kotlin işlevinde, return@label söz diziminin, iç içe yerleştirilmiş çeşitli işlevlerin yanı sıra 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() uygulaması için kullandığınız kalıpla uygulayın.
private suspend fun update(night: SleepNight) {
   withContext(Dispatchers.IO) {
       database.update(night)
   }
}
  1. Tıklama işleyiciyi kullanıcı arayüzüne bağlamak için fragment_sleep_tracker.xml düzen dosyasını açın ve tıklama işleyiciyi stop_button öğesine ekleyin.
android:onClick="@{() -> sleepTrackerViewModel.onStopTracking()}"
  1. Uygulamanızı derleyip çalıştırın.
  2. Başlat'a, ardından Durdur'a dokunun. Başlangıç zamanı, bitiş zamanı, değersiz bir uyku kalitesi ve uyku süresi görürsünüz.

5. Adım: Temizle düğmesi için tıklama işleyiciyi ekleyin

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

suspend fun clear() {
   withContext(Dispatchers.IO) {
       database.clear()
   }
}
  1. Tıklama işleyiciyi kullanıcı arayüzüne bağlamak için fragment_sleep_tracker.xml öğesini açın ve tıklama işleyiciyi clear_button öğesine ekleyin.
android:onClick="@{() -> sleepTrackerViewModel.onClear()}"
  1. Uygulamanızı derleyip çalıştırın.
  2. Tüm verilerden kurtulmak için Temizle'ye dokunun. Daha sonra, 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 bir şekilde çalışmaya devam etmesi için tüm veritabanı işlemleri gibi uzun süreli görevlerde eş yordam kullanın.
  • Korintinler eşzamansızdur ve engelleyici değildir. Eşzamansız kodu sıralı hale getirmek için suspend işlevlerini kullanırlar.
  • Bir eş yordam, suspend ile işaretlenmiş bir işlevi çağırdığında, bu işlev normal bir işlev çağrısı gibi döndürülene kadar engellemek yerine, sonuç hazır olana kadar yürütmeyi askıya alır. Sonra, sonuçta kaldığı yerden devam eder.
  • Engelleme ile askıya alma arasındaki fark, bir ileti dizisi engellendiyse başka bir işin gerçekleşmemesidir. Mesaj dizisi askıya alınırsa sonuç kullanılabilir hale gelene kadar başka çalışmalar gerçekleşir.

Coroutine başlatmak için bir iş, bir görev dağıtıcı ve bir kapsama ihtiyacınız vardır:

  • Temel olarak , iptal edilebilen her şeydir. Her coroutine'in bir işi vardır ve coroutine'i iptal etmek için bir işten yararlanabilirsiniz.
  • Gönderici, çeşitli ileti dizilerinde çalıştırılması için eş yordamlar gönderir. Dispatcher.Main, ana ileti dizisinde görevleri çalıştırırken Dispartcher.IO, engelleme G/Ç görevlerini paylaşılan bir ileti dizisi havuzuna boşaltmak içindir.
  • Kapsam, iş ilanının çalıştırıldığı bağlamı tanımlamak için iş ve görev de dahil olmak üzere bilgileri birleştirir. Kapsamlar, eş yordamları takip eder.

Veritabanı işlemlerini tetikleyen tıklama işleyicileri uygulamak için şu kalıbı uygulayın:

  1. Sonuç, kullanıcı arayüzünü etkilediğinden ana veya kullanıcı arayüzü iş parçacığında çalışan bir eş zamanlı URL başlatın.
  2. Uzun süreli işi yapmak için askıya alma işlevini çağırın. Böylece, sonucu beklerken kullanıcı arayüzü iş parçacığını engellemezsiniz.
  3. Uzun süredir devam eden iş durumunun kullanıcı arayüzüyle bir ilgisi olmadığından G/Ç bağlamına geçin. Böylece çalışma, optimize edilmiş ve bu tür işlemler için ayrılmış bir ileti dizisi havuzunda çalışabilir.
  4. Ardından, işi yapmak için veritabanı işlevini çağırın.

Nesne her değiştiğinde bir LiveData nesnesinden dize oluşturmak için bir Transformations haritası kullanın.

Udacity kursu:

Android Geliştirici Dokümanları:

Diğer dokümanlar ve makaleler:

Bu bölümde, bir eğitmen tarafından sunulan kurs kapsamında bu codelab üzerinden çalışan öğrenciler için olası ev ödevi ödevleri listelenmektedir. Öğretmenin şunları yapması gerekir:

  • Gerekirse ev ödevini atayın.
  • Öğrencilere ev ödevlerinin nasıl gönderileceğini bildirin.
  • Ev ödevlerine not verin.

Öğretmenler bu önerileri istedikleri kadar kullanabilir veya uygun görebilir ve uygun olan diğer ev ödevlerini atayabilirler.

Bu codelab'de kendiniz çalışıyorsanız, bilginizi test etmek için bu ödevlerden yararlanabilirsiniz.

Bu soruları yanıtlayın

1. Soru

Aşağıdakilerden hangisi coroutine'lerin avantajlarından biridir?

  • Engelleme yok
  • Eşzamansız olarak çalışırlar.
  • Bunlar, ana ileti dizisi dışındaki bir ileti dizisinde çalıştırılabilir.
  • Böylece uygulamalar her zaman daha hızlı çalışır.
  • İstisnadan yararlanabilirler.
  • Doğrusal kod olarak yazılıp okunabilirler.

2. Soru

Askıya alma işlevi nedir?

  • suspend anahtar kelimesiyle ek açıklamalı normal bir işlev.
  • Korintinlerin içinde çağrılabilecek bir işlev.
  • Bir askıya alma işlevi çalışırken, çağrı dizisi 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? Tüm doğru olanları işaretleyin.

  • Yürütme engellendiğinde başka bir engellenen ileti dizisi üzerinde işlem yapılamaz.
  • Yürütme askıya alındığında ileti dizisi, kaldırılan çalışmanın tamamlanmasını beklerken başka işlemler yapabilir.
  • İleti dizileri beklenmeyeceği için hiçbir şey yapmayabileceğinden askıya almak daha verimlidir.
  • İster engellenmiş ister askıya alınmış olsun, yürütme işlemi devam etmeden önce eş yordamın sonucunu beklemeye devam eder.

Sonraki derse başlayın: 6.3 Düğme durumlarını kontrol etmek için LiveData'yı kullanma

Bu kurstaki diğer codelab'lerin bağlantılarına ulaşmak için Android Kotlin Fundamentals codelabs açılış sayfasına göz atın.