Android Kotlin Hakkında Temel Bilgiler 07.1: RecyclerView'ın temelleri

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ş

Bu codelab'de, öğe listelerini görüntülemek için RecyclerView nasıl kullanılacağı açıklanmaktadır. Önceki codelab serisindeki uyku takipçisi uygulamasını temel alarak, önerilen mimariye sahip bir RecyclerView kullanarak verileri görüntülemenin daha iyi ve daha çok yönlü bir yolunu öğrenirsiniz.

Bilmeniz gerekenler

Aşağıdaki konular hakkında bilgi sahibi olmanız gerekir:

  • Etkinlik, parçalar ve görünümler kullanarak temel bir kullanıcı arayüzü (UI) oluşturma.
  • Parçalar arasında gezinme ve parçalar arasında veri aktarmak için safeArgs kullanma.
  • Görünüm modelleri, görünüm modeli fabrikaları, dönüşümler ve LiveData ile gözlemcilerini kullanma.
  • Room veritabanı oluşturma, DAO oluşturma ve varlıkları tanımlama
  • Veritabanı görevleri ve uzun süren diğer görevler için eş yordamları kullanma.

Neler öğreneceksiniz?

  • Öğe listesini görüntülemek için RecyclerView ile Adapter ve ViewHolder nasıl kullanılır?

Yapacaklarınız

  • Önceki dersteki TrackMySleepQuality uygulamasını, uyku kalitesi verilerini görüntülemek için RecyclerView kullanacak şekilde değiştirin.

Bu codelab'de, uyku kalitesini takip eden bir uygulamanın RecyclerView bölümünü oluşturacaksınız. Uygulama, uyku verilerini zaman içinde saklamak için Room veritabanını kullanır.

Başlangıç seviyesindeki uyku takipçisi uygulamasında, aşağıdaki şekilde gösterildiği gibi parçalarla temsil edilen iki ekran bulunur.

Solda gösterilen ilk ekranda izlemeyi başlatma ve durdurma düğmeleri bulunur. Bu ekranda kullanıcının tüm uyku verileri de 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.

Bu uygulama, kullanıcı arayüzü denetleyicisi, ViewModel ve LiveData ile basitleştirilmiş bir mimari kullanır. Uygulama, uyku verilerini kalıcı hale getirmek için Room veritabanını da kullanır.

İlk ekranda gösterilen uyku geceleri listesi işlevseldir ancak çok güzel görünmez. Uygulama, metin görünümü için metin dizeleri ve kalite için sayılar oluşturmak üzere karmaşık bir biçimlendirici kullanır. Ayrıca bu tasarım ölçeklenemez. Bu codelab'deki tüm sorunları düzelttikten sonra nihai uygulama aynı işlevselliğe sahip olur ve ana ekran aşağıdaki gibi görünür:

Android'de en sık kullanılan kullanıcı arayüzü görevlerinden biri, veri listesi veya ızgarası görüntülemektir. Listeler basit olabileceği gibi çok karmaşık da olabilir. Metin görünümleri listesinde alışveriş listesi gibi basit veriler gösterilebilir. Tatil yerlerinin açıklamalı listesi gibi karmaşık bir listede, kullanıcıya başlıklar içeren kaydırılabilir bir ızgarada birçok ayrıntı gösterilebilir.

Android, tüm bu kullanım alanlarını desteklemek için RecyclerView widget'ını sunar.

RecyclerView'nın en büyük avantajı, büyük listeler için çok verimli olmasıdır:

  • Varsayılan olarak RecyclerView yalnızca ekranda görünür durumda olan öğeleri işlemek veya çizmek için çalışır. Örneğin, listenizde bin öğe varsa ancak yalnızca 10 öğe görünür durumdaysa RecyclerView, ekranda 10 öğe çizmek için yeterli miktarda işlem yapar. Kullanıcı kaydırdığında RecyclerView, ekranda hangi yeni öğelerin olması gerektiğini belirler ve bu öğeleri görüntülemek için gereken kadar işlem yapar.
  • Ekranın dışına kaydırılan öğelerin görünümleri geri dönüştürülür. Bu durumda, öğe ekrana kaydırılan yeni içerikle doldurulur. Bu RecyclerView davranış, işlem süresini önemli ölçüde kısaltır ve listelerin akıcı bir şekilde kaydırılmasına yardımcı olur.
  • Bir öğe değiştiğinde RecyclerView, listenin tamamını yeniden çizmek yerine yalnızca o öğeyi güncelleyebilir. Bu, karmaşık öğelerin listelerini görüntülerken büyük bir verimlilik artışı sağlar.

Aşağıdaki sırayı incelediğinizde bir görünümün verilerle doldurulduğunu görebilirsiniz ABC. Bu görünüm ekrandan çıktıktan sonra RecyclerView, görünümü yeni veriler için yeniden kullanır XYZ.

Adaptör deseni

Farklı elektrik prizlerinin kullanıldığı ülkeler arasında seyahat ediyorsanız cihazlarınızı adaptör kullanarak prizlere nasıl takabileceğinizi biliyorsunuzdur. Adaptör, bir tür fişi başka bir türe dönüştürmenizi sağlar. Bu da aslında bir arayüzü başka bir arayüze dönüştürmek anlamına gelir.

Yazılım mühendisliğinde adaptör deseni, bir nesnenin başka bir API ile çalışmasına yardımcı olur. RecyclerView, uygulama verilerini RecyclerView'nın gösterebileceği bir şeye dönüştürmek için bir bağdaştırıcı kullanır. Bu işlem sırasında uygulamanın verileri depolama ve işleme şekli değiştirilmez. Uyku izleme uygulaması için, Room veritabanındaki verileri ViewModel'ı değiştirmeden RecyclerView'ın nasıl göstereceğini bildiği bir şeye uyarlayan bir bağdaştırıcı oluşturursunuz.

RecyclerView'ı uygulama

Verilerinizi RecyclerView içinde göstermek için aşağıdaki bölümlere ihtiyacınız vardır:

  • Görüntülenecek veriler.
  • Görünümler için kapsayıcı görevi görecek şekilde düzen dosyanızda tanımlanmış bir RecyclerView örneği.
  • Bir veri öğesinin düzeni.
    Tüm liste öğeleri aynı görünüyorsa hepsi için aynı düzeni kullanabilirsiniz ancak bu zorunlu değildir. Öğe düzeni, parçanın düzeninden ayrı olarak oluşturulmalıdır. Böylece, tek seferde bir öğe görünümü oluşturulabilir ve verilerle doldurulabilir.
  • Düzen yöneticisi.
    Düzen yöneticisi, bir görünümdeki kullanıcı arayüzü bileşenlerinin düzenini yönetir.
  • Görünüm tutucu.
    Görünüm tutucu, ViewHolder sınıfını genişletir. Öğenin düzeninden bir öğeyi görüntülemek için görünüm bilgilerini içerir. Görünüm tutucular, görünümleri ekranda verimli bir şekilde taşımak için kullanılan bilgileri de ekler.RecyclerView
  • Bir bağdaştırıcı.
    Bağdaştırıcı, verilerinizi RecyclerView'ye bağlar. Verileri ViewHolder içinde görüntülenebilecek şekilde uyarlar. Bir RecyclerView, verilerin ekranda nasıl görüntüleneceğini belirlemek için bağdaştırıcıyı kullanır.

Bu görevde, düzen dosyanıza RecyclerView ekleyip uyku verilerini RecyclerView'ya göstermek için Adapter ayarlayacaksınız.

1. adım: LayoutManager ile RecyclerView ekleyin

Bu adımda, fragment_sleep_tracker.xml dosyasında ScrollView yerine RecyclerView yazacaksınız.

  1. GitHub'dan RecyclerViewFundamentals-Starter uygulamasını indirin.
  2. Uygulamayı oluşturup çalıştırın. Verilerin nasıl basit metin olarak gösterildiğine dikkat edin.
  3. Android Studio'daki Tasarım sekmesinde fragment_sleep_tracker.xml düzen dosyasını açın.
  4. Bileşen Ağacı bölmesinde ScrollView öğesini silin. Bu işlem, ScrollView içindeki TextView öğesini de siler.
  5. Palet bölmesinde, soldaki bileşen türleri listesinde Kapsayıcılar'ı bulup seçin.
  6. RecyclerView simgesini Palet bölmesinden Bileşen Ağacı bölmesine sürükleyin. RecyclerView cihazını ConstraintLayout içine yerleştirin.

  1. Bağımlılık eklemek isteyip istemediğinizi soran bir iletişim kutusu açılırsa Android Studio'nun recyclerview bağımlılığını Gradle dosyanıza eklemesine izin vermek için Tamam'ı tıklayın. Bu işlem birkaç saniye sürebilir. Ardından uygulamanız senkronize edilir.

  1. Modül build.gradle dosyasını açın, sonuna gidin ve aşağıdaki koda benzeyen yeni bağımlı öğeyi not edin:
implementation 'androidx.recyclerview:recyclerview:1.0.0'
  1. fragment_sleep_tracker.xml'a geri dönün.
  2. Metin sekmesinde, aşağıda gösterilen RecyclerView kodunu bulun:
<androidx.recyclerview.widget.RecyclerView
   android:layout_width="match_parent"
   android:layout_height="match_parent" />
  1. RecyclerView için id sleep_list verin.
android:id="@+id/sleep_list"
  1. RecyclerView simgesini, ConstraintLayout simgesinin içindeki ekranın kalan kısmını kaplayacak şekilde konumlandırın. Bunu yapmak için RecyclerView simgesinin üst kısmını Başlat düğmesiyle, alt kısmını Temizle düğmesiyle ve her iki tarafını da üst öğeyle sınırlayın. Düzen Düzenleyici'de veya XML'de aşağıdaki kodu kullanarak düzen genişliğini ve yüksekliğini 0 dp olarak ayarlayın:
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:layout_constraintBottom_toTopOf="@+id/clear_button"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/stop_button"
  1. RecyclerView XML'sine bir düzen yöneticisi ekleyin. Her RecyclerView, listedeki öğelerin nasıl konumlandırılacağını belirten bir düzen yöneticisine ihtiyaç duyar. Android, öğeleri varsayılan olarak tam genişlikteki satırlardan oluşan dikey bir listede düzenleyen bir LinearLayoutManager sağlar.
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
  1. Tasarım sekmesine geçin ve eklenen kısıtlamaların RecyclerView simgesinin kullanılabilir alanı dolduracak şekilde genişlemesine neden olduğunu fark edin.

2. adım: Liste öğesi düzenini ve metin görünümü tutucusunu oluşturun

RecyclerView yalnızca bir kapsayıcıdır. Bu adımda, RecyclerView içinde gösterilecek öğelerin düzenini ve altyapısını oluşturursunuz.

Çalışan bir RecyclerView'ya olabildiğince hızlı ulaşmak için başlangıçta yalnızca uyku kalitesini sayı olarak gösteren basit bir liste öğesi kullanırsınız. Bunun için bir görünüm tutucuya (TextItemViewHolder) ihtiyacınız vardır. Veriler için bir görünüm (TextView) de gerekir. (Daha sonraki bir adımda, görünüm tutucular ve tüm uyku verilerini nasıl düzenleyeceğiniz hakkında daha fazla bilgi edineceksiniz.)

  1. text_item_view.xml adlı bir düzen dosyası oluşturun. Şablon kodunu değiştireceğiniz için kök öğe olarak ne kullandığınız önemli değildir.
  2. text_item_view.xml bölümünde, verilen tüm kodu silin.
  3. Başında ve sonunda 16dp dolgusu olan bir TextView ekleyin ve metin boyutunu 24sp olarak ayarlayın. Genişlik üst öğeyle eşleşsin, yükseklik ise içeriği sarsın. Bu görünüm RecyclerView içinde gösterildiğinden görünümü ViewGroup içine yerleştirmeniz gerekmez.
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:textSize="24sp"
    android:paddingStart="16dp"
    android:paddingEnd="16dp"
    android:layout_width="match_parent"       
    android:layout_height="wrap_content" />
  1. Util.kt adlı kişiyi aç. En sona gidin ve TextItemViewHolder sınıfını oluşturan aşağıdaki tanımı ekleyin. Kodu, dosyanın en altına, son kapanış ayracından sonra yerleştirin. Bu görünüm tutucu geçici olduğundan ve daha sonra değiştireceğiniz için kod Util.kt içine yerleştirilir.
class TextItemViewHolder(val textView: TextView): RecyclerView.ViewHolder(textView)
  1. İstenirse android.widget.TextView ve androidx.recyclerview.widget.RecyclerView dosyalarını içe aktarın.

3. adım: SleepNightAdapter oluşturun

RecyclerView uygulamasındaki temel görev, bağdaştırıcıyı oluşturmaktır. Öğe görünümü için basit bir görünüm tutucunuz ve her öğe için bir düzeniniz vardır. Artık bağdaştırıcı oluşturabilirsiniz. Adaptör, bir görünüm tutucu oluşturur ve RecyclerView için görüntülenecek verilerle doldurur.

  1. sleeptracker paketinde SleepNightAdapter adlı yeni bir Kotlin sınıfı oluşturun.
  2. SleepNightAdapter sınıfını RecyclerView.Adapter sınıfını genişletecek şekilde oluşturun. Bu sınıfa SleepNightAdapter adı verilir. Çünkü SleepNight nesnesini RecyclerView tarafından kullanılabilecek bir şeye dönüştürür. Bağdaştırıcının hangi görünüm tutucusunu kullanacağını bilmesi gerekir. Bu nedenle, TextItemViewHolder değerini iletin. İstendiğinde gerekli bileşenleri içe aktarın. Ardından, uygulanması zorunlu yöntemler olduğundan bir hata görürsünüz.
class SleepNightAdapter: RecyclerView.Adapter<TextItemViewHolder>() {}
  1. SleepNightAdapter'nın en üst düzeyinde, verileri tutmak için bir listOf SleepNight değişkeni oluşturun.
var data =  listOf<SleepNight>()
  1. SleepNightAdapter içinde, data'deki uyku geceleri listesinin boyutunu döndürmek için getItemCount() değerini geçersiz kılın. RecyclerView, görüntüleyeceği öğe sayısını bilmelidir. Bunu da getItemCount() işlevini çağırarak yapar.
override fun getItemCount() = data.size
  1. SleepNightAdapter içinde, aşağıda gösterildiği gibi onBindViewHolder() işlevini geçersiz kılın.

    onBindViewHolder() işlevi, belirtilen konumdaki bir liste öğesinin verilerini görüntülemek için RecyclerView tarafından çağrılır. Bu nedenle onBindViewHolder() yöntemi iki bağımsız değişken alır: görünüm tutucu ve bağlanacak verilerin konumu. Bu uygulamada, kart sahibi TextItemViewHolder, konum ise listedeki konumdur.
override fun onBindViewHolder(holder: TextItemViewHolder, position: Int) {
}
  1. onBindViewHolder() içinde, verilerde belirli bir konumdaki bir öğe için değişken oluşturun.
 val item = data[position]
  1. Oluşturduğunuz ViewHolder, textView adlı bir mülke sahip. onBindViewHolder() içinde, textView öğesinin text değerini uyku kalitesi numarasına ayarlayın. Bu kod yalnızca bir sayı listesi gösterir ancak bu basit örnek, bağdaştırıcının verileri nasıl görünüm tutucuya ve ekrana getirdiğini görmenizi sağlar.
holder.textView.text = item.sleepQuality.toString()
  1. SleepNightAdapter içinde, RecyclerView bir öğeyi temsil etmek için görünüm tutucuya ihtiyaç duyduğunda çağrılan onCreateViewHolder() işlevini geçersiz kılın ve uygulayın.

    Bu işlev iki parametre alır ve ViewHolder döndürür. Görünüm tutucuyu barındıran görünüm grubu olan parent parametresi her zaman RecyclerView olur. viewType parametresi, aynı RecyclerView içinde birden fazla görünüm olduğunda kullanılır. Örneğin, bir metin görünümü listesini, bir resmi ve bir videoyu aynı RecyclerView içine yerleştirirseniz onCreateViewHolder() işlevinin hangi tür görünümü kullanacağını bilmesi gerekir.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TextItemViewHolder {
}
  1. onCreateViewHolder() içinde LayoutInflater örneği oluşturun.

    Düzen genişletici, XML düzenlerinden nasıl görünüm oluşturulacağını bilir. context, görüntülemeyi doğru şekilde artırma hakkında bilgiler içerir. Bir geri dönüşüm görünümü için bağdaştırıcıda, her zaman parent görünüm grubunun bağlamını (RecyclerView) iletirsiniz.
val layoutInflater = LayoutInflater.from(parent.context)
  1. onCreateViewHolder() içinde, layoutinflater'dan view şişirmesini isteyerek view oluşturun.

    Görünüm için XML düzenini ve görünüm için parent görünüm grubunu iletin. Üçüncü bağımsız değişken olan boole bağımsız değişkeni attachToRoot'dır. Bu bağımsız değişken false olmalıdır. Çünkü RecyclerView, zamanı geldiğinde bu öğeyi görünüm hiyerarşisine sizin için ekler.
val view = layoutInflater
       .inflate(R.layout.text_item_view, parent, false) as TextView
  1. onCreateViewHolder() içinde view ile oluşturulan TextItemViewHolder değerini döndürün.
return TextItemViewHolder(view)
  1. RecyclerView, veriler hakkında hiçbir şey bilmediğinden data değiştiğinde bağdaştırıcının RecyclerView'yı bilgilendirmesi gerekir. Yalnızca bağdaştırıcının kendisine verdiği görünüm tutucular hakkında bilgi sahibidir.

    Görüntülediği veriler değiştiğinde RecyclerView öğesine bilgi vermek için SleepNightAdapter sınıfının en üstündeki data değişkenine özel bir ayarlayıcı ekleyin. Ayarlayıcıda data için yeni bir değer verin, ardından notifyDataSetChanged() işlevini çağırarak listenin yeni verilerle yeniden çizilmesini tetikleyin.
var data =  listOf<SleepNight>()
   set(value) {
       field = value
       notifyDataSetChanged()
   }

4. adım: RecyclerView'a Adapter hakkında bilgi verin

RecyclerView, görünüm tutucuları almak için kullanılacak bağdaştırıcı hakkında bilgi sahibi olmalıdır.

  1. SleepTrackerFragment.kt adlı kişiyi aç.
  2. onCreateview() içinde bir bağdaştırıcı oluşturun. Bu kodu, ViewModel modeli oluşturulduktan sonra ve return ifadesinden önce yerleştirin.
val adapter = SleepNightAdapter()
  1. adapter ile RecyclerView'yi ilişkilendirin.
binding.sleepList.adapter = adapter
  1. binding nesnesini güncellemek için projenizi temizleyip yeniden oluşturun.

    binding.sleepList veya binding.FragmentSleepTrackerBinding ile ilgili hataları görmeye devam ederseniz önbellekleri geçersiz kılın ve yeniden başlatın. (Dosya > Geçersiz Kılınan Önbellekler / Yeniden Başlat'ı seçin.)

    Uygulamayı şimdi çalıştırırsanız hata olmaz ancak Başlat'a, ardından Durdur'a dokunduğunuzda herhangi bir veri gösterilmez.

5. adım: Adaptöre veri aktarın

Şu ana kadar bir adaptörünüz ve adaptörden RecyclerView'ya veri aktarmanın bir yolu var. Şimdi ViewModel'dan bağdaştırıcıya veri aktarmanız gerekiyor.

  1. SleepTrackerViewModel adlı kişiyi aç.
  2. Gösterilecek veriler olan tüm uyku gecelerini depolayan nights değişkenini bulun. nights değişkeni, veritabanında getAllNights() çağrılarak ayarlanır.
  3. Bu değişkene erişmesi gereken bir gözlemci oluşturacağınız için private değişkenini nights öğesinden kaldırın. Beyanınız aşağıdaki gibi görünmelidir:
val nights = database.getAllNights()
  1. database paketinde SleepDatabaseDao dosyasını açın.
  2. getAllNights() işlevini bulun. Bu işlevin, SleepNight değerlerinin listesini LiveData olarak döndürdüğünü unutmayın. Bu, nights değişkeninin Room tarafından güncel tutulan LiveData içerdiği ve ne zaman değiştiğini öğrenmek için nights değişkenini gözlemleyebileceğiniz anlamına gelir.
  3. SleepTrackerFragment adlı kişiyi aç.
  4. onCreateView() içinde, adapter oluşturulduktan sonra nights değişkeninde bir gözlemci oluşturun. Parçanın viewLifecycleOwner öğesini yaşam döngüsü sahibi olarak sağlayarak bu gözlemcinin yalnızca RecyclerView ekrandayken etkin olmasını sağlayabilirsiniz.

sleepTrackerViewModel.nights.observe(viewLifecycleOwner, Observer {
   })
  1. Gözlemcinin içinde, boş olmayan bir değer (nights için) aldığınızda değeri bağdaştırıcının data öğesine atayın. Bu, gözlemci için tamamlanmış kod ve verilerin ayarlanmasıdır:
sleepTrackerViewModel.nights.observe(viewLifecycleOwner, Observer {
   it?.let {
       adapter.data = it
   }
})
  1. Kodunuzu oluşturup çalıştırın.

    Adaptörünüz çalışıyorsa uyku kalitesiyle ilgili sayıları liste olarak görürsünüz. Soldaki ekran görüntüsünde, Başlat'a dokunduktan sonra -1 gösteriliyor. Sağdaki ekran görüntüsünde, Durdur'a dokunup kalite derecesi seçtikten sonra güncellenen uyku kalitesi sayısı gösterilmektedir.

6. adım: Görüntüleme kartlarının nasıl geri dönüştürüldüğünü inceleyin

RecyclerView Görünüm tutucuları geri dönüştürür. Bu, görünüm tutucuların yeniden kullanıldığı anlamına gelir. Bir görünüm ekranın dışına kaydırıldığında RecyclerView, ekranın içine kaydırılacak görünüm için görünümü yeniden kullanır.

Bu görünüm tutucular geri dönüştürüldüğünden onBindViewHolder(), önceki öğelerin görünüm tutucuda ayarlamış olabileceği tüm özelleştirmeleri ayarlar veya sıfırlar.

Örneğin, 1'e eşit veya 1'den küçük kalite derecelendirmelerini içeren ve kötü uyku kalitesini temsil eden görünüm tutucularda metin rengini kırmızı olarak ayarlayabilirsiniz.

  1. SleepNightAdapter sınıfında, onBindViewHolder() öğesinin sonuna aşağıdaki kodu ekleyin.
if (item.sleepQuality <= 1) {
   holder.textView.setTextColor(Color.RED) // red
}
  1. Uygulamayı çalıştırın.
  2. Uyku kalitesi düşük veriler eklediğinizde sayı kırmızı olur.
  3. Ekranda kırmızı renkte yüksek bir sayı görene kadar uyku kalitesi için yüksek puanlar ekleyin.

    RecyclerView, görünüm tutucuları yeniden kullandığı için sonunda yüksek kaliteli bir puan için kırmızı görünüm tutuculardan birini yeniden kullanır. Yüksek puan yanlışlıkla kırmızı renkte gösteriliyor.

  1. Bu sorunu düzeltmek için kalite değeri birden küçük veya bire eşit değilse rengi siyah olarak ayarlayan bir else ifadesi ekleyin.

    Her iki koşul da açıkça belirtildiğinde görünüm tutucu, her öğe için doğru metin rengini kullanır.
if (item.sleepQuality <= 1) {
   holder.textView.setTextColor(Color.RED) // red
} else {
   // reset
   holder.textView.setTextColor(Color.BLACK) // black
}
  1. Uygulamayı çalıştırın. Sayılar her zaman doğru renkte olmalıdır.

Tebrikler! Artık tamamen işlevsel bir temel RecyclerView hesabınız var.

Bu görevde, basit görünüm tutucuyu bir uyku gecesiyle ilgili daha fazla veri gösterebilen bir tutucuyla değiştireceksiniz.

Util.kt öğesine eklediğiniz basit ViewHolder, yalnızca TextView öğesini TextItemViewHolder içine sarar.

class TextItemViewHolder(val textView: TextView): RecyclerView.ViewHolder(textView)

Peki neden RecyclerView doğrudan TextView kullanmıyor? Bu tek kod satırı birçok işlev sunar. ViewHolder, bir öğe görünümünü ve RecyclerView içindeki yeriyle ilgili meta verileri açıklar. RecyclerView, görünümü liste kaydırılırken doğru şekilde konumlandırmak ve Adapter'ye öğe eklenip kaldırıldığında görünümlere animasyon eklemek gibi ilgi çekici işlemler yapmak için bu işlevden yararlanır.

RecyclerView, ViewHolder içinde depolanan görünümlere erişmesi gerekiyorsa görünüm tutucunun itemView özelliğini kullanarak bunu yapabilir. RecyclerView, ekranda gösterilecek bir öğeyi bağlarken, bir görünümün etrafına kenarlık gibi süslemeler çizerken ve erişilebilirliği uygularken itemView kullanır.

1. adım: Öğenin düzenini oluşturun

Bu adımda bir öğe için düzen dosyasını oluşturursunuz. Düzende, uyku kalitesi için ConstraintLayout, uyku süresi için ImageView ve kalite için TextView simgesi ile kaliteyi metin olarak gösteren bir TextView yer alır. Daha önce düzen oluşturduğunuz için sağlanan XML kodunu kopyalayıp yapıştırın.

  1. Yeni bir düzen kaynak dosyası oluşturun ve dosyayı list_item_sleep_night olarak adlandırın.
  2. Dosyadaki tüm kodu aşağıdaki kodla değiştirin. Ardından, yeni oluşturduğunuz düzeni inceleyin.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="wrap_content">

   <ImageView
       android:id="@+id/quality_image"
       android:layout_width="@dimen/icon_size"
       android:layout_height="60dp"
       android:layout_marginStart="16dp"
       android:layout_marginTop="8dp"
       android:layout_marginBottom="8dp"
       app:layout_constraintBottom_toBottomOf="parent"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toTopOf="parent"
       tools:srcCompat="@drawable/ic_sleep_5" />

   <TextView
       android:id="@+id/sleep_length"
       android:layout_width="0dp"
       android:layout_height="20dp"
       android:layout_marginStart="8dp"
       android:layout_marginTop="8dp"
       android:layout_marginEnd="16dp"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintStart_toEndOf="@+id/quality_image"
       app:layout_constraintTop_toTopOf="@+id/quality_image"
       tools:text="Wednesday" />

   <TextView
       android:id="@+id/quality_string"
       android:layout_width="0dp"
       android:layout_height="20dp"
       android:layout_marginTop="8dp"
       app:layout_constraintEnd_toEndOf="@+id/sleep_length"
       app:layout_constraintHorizontal_bias="0.0"
       app:layout_constraintStart_toStartOf="@+id/sleep_length"
       app:layout_constraintTop_toBottomOf="@+id/sleep_length"
       tools:text="Excellent!!!" />
</androidx.constraintlayout.widget.ConstraintLayout>
  1. Android Studio'da Tasarım sekmesine geçin. Tasarım görünümünde düzeniniz aşağıdaki soldaki ekran görüntüsüne benzer. Plan görünümünde, sağdaki ekran görüntüsüne benzer.

2. adım: ViewHolder oluşturun

  1. SleepNightAdapter.kt adlı kişiyi aç.
  2. SleepNightAdapter içinde ViewHolder adlı bir sınıf oluşturun ve bu sınıfı RecyclerView.ViewHolder olarak genişletin.
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){}
  1. ViewHolder içinde görünümlere referanslar alın. Bu ViewHolder öğesinin güncelleyeceği görünümlere referans vermeniz gerekir. Bu ViewHolder öğesini her bağladığınızda resme ve her iki metin görünümüne erişmeniz gerekir. (Bu kodu daha sonra veri bağlama kullanacak şekilde dönüştüreceksiniz.)
val sleepLength: TextView = itemView.findViewById(R.id.sleep_length)
val quality: TextView = itemView.findViewById(R.id.quality_string)
val qualityImage: ImageView = itemView.findViewById(R.id.quality_image)

3. adım: ViewHolder'ı SleepNightAdapter'da kullanın

  1. SleepNightAdapter tanımında TextItemViewHolder yerine yeni oluşturduğunuz SleepNightAdapter.ViewHolder öğesini kullanın.
class SleepNightAdapter: RecyclerView.Adapter<SleepNightAdapter.ViewHolder>() {

onCreateViewHolder() adresini güncelleyin:

  1. ViewHolder değerini döndürmek için onCreateViewHolder() işlevinin imzasını değiştirin.
  2. Düzen genişleticiyi doğru düzen kaynağını (list_item_sleep_night) kullanacak şekilde değiştirin.
  3. TextView cihazına yayınlama işlemini kaldırın.
  4. TextItemViewHolder yerine ViewHolder döndürün.

    Güncellenmiş onCreateViewHolder() işlevi tamamlandı:
    override fun onCreateViewHolder(
            parent: ViewGroup, viewType: Int): ViewHolder {
        val layoutInflater = 
            LayoutInflater.from(parent.context)
        val view = layoutInflater
                .inflate(R.layout.list_item_sleep_night, 
                         parent, false)
        return ViewHolder(view)
    }

onBindViewHolder() adresini güncelleyin:

  1. onBindViewHolder() işlevinin imzasını, holder parametresi TextItemViewHolder yerine ViewHolder olacak şekilde değiştirin.
  2. onBindViewHolder() içinde, item tanımı hariç tüm kodu silin.
  3. Bu görünüm için resources öğesine referans içeren bir val res tanımlayın.
val res = holder.itemView.context.resources
  1. sleepLength metin görünümünün metnini süre olarak ayarlayın. Başlangıç koduyla birlikte sağlanan bir biçimlendirme işlevini çağıran aşağıdaki kodu kopyalayın.
holder.sleepLength.text = convertDurationToFormatted(item.startTimeMilli, item.endTimeMilli, res)
  1. Bu işlem, convertDurationToFormatted() tanımlanması gerektiğinden hata verir. Util.kt bağlantısını açın ve kodun yorumunu kaldırıp ilişkili içe aktarmaları yapın. (Kod > Satır yorumlarıyla yorum yap'ı seçin.)
  2. onBindViewHolder()'ya geri dönün ve kaliteyi ayarlamak için convertNumericQualityToString()'ı kullanın.
holder.quality.text= convertNumericQualityToString(item.sleepQuality, res)
  1. Bu işlevleri manuel olarak içe aktarmanız gerekebilir.
import com.example.android.trackmysleepquality.convertDurationToFormatted
import com.example.android.trackmysleepquality.convertNumericQualityToString
  1. Kalite için doğru simgeyi ayarlayın. Başlangıç kodunda yeni ic_sleep_active simgesi sağlanır.
holder.qualityImage.setImageResource(when (item.sleepQuality) {
   0 -> R.drawable.ic_sleep_0
   1 -> R.drawable.ic_sleep_1
   2 -> R.drawable.ic_sleep_2
   3 -> R.drawable.ic_sleep_3
   4 -> R.drawable.ic_sleep_4
   5 -> R.drawable.ic_sleep_5
   else -> R.drawable.ic_sleep_active
})
  1. onBindViewHolder() işlevinin güncellenmiş ve tamamlanmış halini aşağıda bulabilirsiniz. Bu işlev, ViewHolder için tüm verileri ayarlar:
   override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val item = data[position]
        val res = holder.itemView.context.resources
        holder.sleepLength.text = convertDurationToFormatted(item.startTimeMilli, item.endTimeMilli, res)
        holder.quality.text= convertNumericQualityToString(item.sleepQuality, res)
        holder.qualityImage.setImageResource(when (item.sleepQuality) {
            0 -> R.drawable.ic_sleep_0
            1 -> R.drawable.ic_sleep_1
            2 -> R.drawable.ic_sleep_2
            3 -> R.drawable.ic_sleep_3
            4 -> R.drawable.ic_sleep_4
            5 -> R.drawable.ic_sleep_5
            else -> R.drawable.ic_sleep_active
        })
    }
  1. Uygulamanızı çalıştırın. Ekranınız aşağıdaki ekran görüntüsüne benzemeli, uyku süresi ve uyku kalitesiyle ilgili metinlerin yanı sıra uyku kalitesi simgesini göstermelidir.

RecyclerView tamamlandı. Adapter ve ViewHolder bileşenlerini nasıl uygulayacağınızı öğrendiniz ve bunları bir araya getirerek RecyclerView Adapter içeren bir liste görüntülediniz.

Şu ana kadar yazdığınız kodda, bağdaştırıcı ve görünüm tutucu oluşturma süreci gösteriliyor. Ancak bu kodu iyileştirebilirsiniz. Görüntülenecek kod ile görünüm tutucuları yönetme kodu karıştırılmış ve onBindViewHolder(), ViewHolder güncelleme hakkında ayrıntılı bilgiye sahip.

Üretim uygulamasında birden fazla görünüm tutucu, daha karmaşık bağdaştırıcılar ve değişiklik yapan birden fazla geliştirici olabilir. Kodunuzu, görünüm tutucuyla ilgili her şeyin yalnızca görünüm tutucuda olacağı şekilde yapılandırmalısınız.

1. adım: onBindViewHolder() işlevini yeniden düzenleyin

Bu adımda kodu yeniden düzenleyip tüm görünüm tutucu işlevlerini ViewHolder içine taşıyacaksınız. Bu yeniden düzenlemenin amacı, uygulamanın kullanıcıya nasıl göründüğünü değiştirmek değil, geliştiricilerin kod üzerinde çalışmasını kolaylaştırmak ve daha güvenli hale getirmektir. Neyse ki Android Studio'da bu konuda yardımcı olacak araçlar bulunur.

  1. SleepNightAdapter bölümünde, onBindViewHolder() bölümünde, değişkeni bildirmek için kullanılan ifade item dışındaki her şeyi seçin.
  2. Sağ tıklayın, ardından Yeniden düzenle > Ayıkla > İşlev'i seçin.
  3. İşlevi bind olarak adlandırın ve önerilen parametreleri kabul edin. Tamam'ı tıklayın.

    bind() işlevi, onBindViewHolder()'nin altına yerleştirilir.
    private fun bind(holder: ViewHolder, item: SleepNight) {
        val res = holder.itemView.context.resources
        holder.sleepLength.text = convertDurationToFormatted(item.startTimeMilli, item.endTimeMilli, res)
        holder.quality.text = convertNumericQualityToString(item.sleepQuality, res)
        holder.qualityImage.setImageResource(when (item.sleepQuality) {
            0 -> R.drawable.ic_sleep_0
            1 -> R.drawable.ic_sleep_1
            2 -> R.drawable.ic_sleep_2
            3 -> R.drawable.ic_sleep_3
            4 -> R.drawable.ic_sleep_4
            5 -> R.drawable.ic_sleep_5
            else -> R.drawable.ic_sleep_active
        })
    }
  1. İmleci, bind() parametresinin holder kelimesinin üzerine getirin.holder Amacınıza uygun menüyü açmak için Alt+Enter (Mac'te Option+Enter) tuşuna basın. Bunu aşağıdaki imzaya sahip bir uzantı işlevine dönüştürmek için Parametreyi alıcıya dönüştür'ü seçin:
private fun ViewHolder.bind(item: SleepNight) {...}
  1. bind() işlevini kesip ViewHolder aralığına yapıştırın.
  2. bind() herkese açık hâle getirin.
  3. Gerekirse bind() öğesini adaptöre aktarın.
  4. Artık ViewHolder içinde olduğu için imzanın ViewHolder bölümünü kaldırabilirsiniz. ViewHolder sınıfındaki bind() işlevinin son kodu aşağıda verilmiştir.
fun bind(item: SleepNight) {
   val res = itemView.context.resources
   sleepLength.text = convertDurationToFormatted(
           item.startTimeMilli, item.endTimeMilli, res)
   quality.text = convertNumericQualityToString(
           item.sleepQuality, res)
   qualityImage.setImageResource(when (item.sleepQuality) {
       0 -> R.drawable.ic_sleep_0
       1 -> R.drawable.ic_sleep_1
       2 -> R.drawable.ic_sleep_2
       3 -> R.drawable.ic_sleep_3
       4 -> R.drawable.ic_sleep_4
       5 -> R.drawable.ic_sleep_5
       else -> R.drawable.ic_sleep_active
   })
}

2. adım: onCreateViewHolder'ı yeniden düzenleyin

Adaptördeki onCreateViewHolder() yöntemi, şu anda ViewHolder için görünümü düzen kaynağındaki görünümden şişiriyor. Ancak enflasyonun adaptörle hiçbir ilgisi yoktur ve her şey ViewHolder ile ilgilidir. Enflasyon ViewHolder içinde gerçekleşmelidir.

  1. onCreateViewHolder() bölümünde, işlevin gövdesindeki tüm kodu seçin.
  2. Sağ tıklayın, ardından Yeniden düzenle > Ayıkla > İşlev'i seçin.
  3. İşlevi from olarak adlandırın ve önerilen parametreleri kabul edin. Tamam'ı tıklayın.
  4. İmleci işlev adının üzerine getirin from. Amacınıza uygun menüyü açmak için Alt+Enter (Mac'te Option+Enter) tuşuna basın.
  5. Yardımcı nesneye taşı'yı seçin. from() işlevinin, ViewHolder sınıfında çağrılabilmesi için yardımcı nesnede olması gerekir. ViewHolder örneğinde çağrılamaz.
  6. companion nesnesini ViewHolder sınıfına taşıyın.
  7. from() herkese açık hâle getirin.
  8. onCreateViewHolder() içinde, return ifadesini ViewHolder sınıfında from() çağrısının sonucunu döndürecek şekilde değiştirin.

    Tamamlanmış onCreateViewHolder() ve from() yöntemleriniz aşağıdaki koda benzemeli ve kodunuz hatasız olarak oluşturulup çalıştırılmalıdır.
    override fun onCreateViewHolder(parent: ViewGroup, viewType: 
Int): ViewHolder {
        return ViewHolder.from(parent)
    }
companion object {
   fun from(parent: ViewGroup): ViewHolder {
       val layoutInflater = LayoutInflater.from(parent.context)
       val view = layoutInflater
               .inflate(R.layout.list_item_sleep_night, parent, false)
       return ViewHolder(view)
   }
}
  1. ViewHolder sınıfının imzasını, oluşturucunun özel olacak şekilde değiştirin. from() artık yeni bir ViewHolder örneği döndüren bir yöntem olduğundan kimsenin ViewHolder oluşturucusunu çağırmasına gerek kalmadı.
class ViewHolder private constructor(itemView: View) : RecyclerView.ViewHolder(itemView){
  1. Uygulamayı çalıştırın. Uygulamanız, yeniden düzenlemeden sonraki istenen sonuç olarak eskisi gibi derlenip çalıştırılmalıdır.

Android Studio projesi: RecyclerViewFundamentals

  • Android'de en sık kullanılan kullanıcı arayüzü görevlerinden biri, veri listesi veya ızgarası görüntülemektir. RecyclerView, çok büyük listeleri görüntülerken bile verimli olacak şekilde tasarlanmıştır.
  • RecyclerView yalnızca ekranda görünür durumda olan öğeleri işlemek veya çizmek için gereken işlemleri yapar.
  • Ekranın dışına kaydırılan öğelerin görünümleri geri dönüştürülür. Bu durumda, öğe ekrana kaydırılan yeni içerikle doldurulur.
  • Yazılım mühendisliğinde adaptör deseni, bir nesnenin başka bir API ile birlikte çalışmasına yardımcı olur. RecyclerView, uygulama verilerini görüntüleyebileceği bir şeye dönüştürmek için bir bağdaştırıcı kullanır. Bu işlem için uygulamanın verileri depolama ve işleme şeklinin değiştirilmesi gerekmez.

Verilerinizi RecyclerView içinde göstermek için aşağıdaki bölümlere ihtiyacınız vardır:

  • RecyclerView
    : RecyclerView örneği oluşturmak için düzen dosyasında <RecyclerView> öğesini tanımlayın.
  • LayoutManager
    A RecyclerView, RecyclerView içindeki öğelerin düzenini (ör. öğeleri bir ızgarada veya doğrusal bir listede düzenleme) organize etmek için LayoutManager kullanır.

    Düzen dosyasındaki <RecyclerView> içinde, app:layoutManager özelliğini düzen yöneticisine (ör. LinearLayoutManager veya GridLayoutManager) ayarlayın.

    RecyclerView için LayoutManager değerini programatik olarak da ayarlayabilirsiniz. (Bu teknik, sonraki bir codelab'de ele alınacaktır.)
  • Her öğe için düzen
    Bir XML düzen dosyasında bir veri öğesi için düzen oluşturun.
  • Adaptör
    Verileri hazırlayan ve ViewHolder içinde nasıl görüntüleneceğini belirleyen bir adaptör oluşturun. Adaptörü RecyclerView ile ilişkilendirin.

    RecyclerView çalıştırıldığında verilerin ekranda nasıl gösterileceğini belirlemek için bağdaştırıcıyı kullanır.

    Bağdaştırıcı, aşağıdaki yöntemleri uygulamanızı gerektirir:
    – Öğelerin sayısını döndürmek için getItemCount().
    – Listedeki bir öğenin ViewHolder değerini döndürmek için onCreateViewHolder().
    – Listedeki bir öğenin verilerini görünümlere uyarlamak için onBindViewHolder().

  • ViewHolder
    : Bir ViewHolder, öğe düzeninden bir öğeyi görüntülemek için görünüm bilgilerini içerir.
  • Adaptördeki onBindViewHolder() yöntemi, verileri görünümlere uyarlar. Bu yöntemi her zaman geçersiz kılarsınız. Genellikle onBindViewHolder(), bir öğenin düzenini şişirir ve verileri düzendeki görünümlere yerleştirir.
  • RecyclerView veriler hakkında hiçbir şey bilmediğinden, bu veriler değiştiğinde Adapter, RecyclerView'yı bilgilendirmelidir. Verilerin değiştiğini Adapter bildirmek için notifyDataSetChanged() kullanın.

Udacity kursu:

Android geliştirici belgeleri:

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

RecyclerView öğeleri nasıl gösterir? Uygun olan tüm seçenekleri işaretleyin.

▢ Öğeleri listede veya ızgarada gösterir.

▢ Dikey veya yatay olarak kaydırılır.

▢ Tablet gibi daha büyük cihazlarda çapraz kaydırılır.

▢ Liste veya ızgara kullanım alanı için yeterli olmadığında özel düzenlere izin verir.

2. Soru

RecyclerView kullanmanın avantajları nelerdir? Uygun olan tüm seçenekleri işaretleyin.

▢ Büyük listeleri verimli bir şekilde gösterir.

▢ Verileri otomatik olarak günceller.

▢ Bir öğe güncellendiğinde, silindiğinde veya listeye eklendiğinde yenileme ihtiyacını en aza indirir.

▢ Ekranı kaydırarak görüntüden çıkan görünümü, ekranda kaydırılan bir sonraki öğeyi göstermek için yeniden kullanır.

3. Soru

Adaptör kullanmanın nedenleri nelerdir? Uygun olan tüm seçenekleri işaretleyin.

▢ İlgi alanlarının ayrılması, kodun değiştirilmesini ve test edilmesini kolaylaştırır.

RecyclerView, gösterilen verilerden bağımsızdır.

▢ Veri işleme katmanları, verilerin nasıl görüntüleneceğiyle ilgilenmek zorunda değildir.

▢ Uygulama daha hızlı çalışır.

4. Soru

Aşağıdakilerden hangisi ViewHolder için doğrudur? Uygun olan tüm seçenekleri işaretleyin.

ViewHolder düzeni, XML düzen dosyalarında tanımlanır.

▢ Veri kümesindeki her veri birimi için bir ViewHolder vardır.

▢ Bir RecyclerView içinde birden fazla ViewHolder olabilir.

Adapter, verileri ViewHolder'ye bağlar.

Bir sonraki derse başlayın: 7.2: RecyclerView ile DiffUtil ve veri bağlama