Android Kotlin Fundamentals 07.1: RecyclerView ile ilgili temel bilgiler

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ş

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

Bilmeniz gerekenler

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

  • Bir etkinlik, parçalar ve görünümler kullanarak temel kullanıcı arayüzü (UI) oluşturma.
  • Parçalar arasında gezinme ve parçaları parçalar arasında aktarmak için safeArgs kullanma.
  • Görünüm modellerini kullanarak model fabrikalarını, dönüşümleri, LiveData ve gözlemcilerini görüntüleyin.
  • Room veritabanı oluşturma, DAO oluşturma ve varlıkları tanımlama.
  • Veritabanı görevleri ve uzun süreli diğer görevler için eş yordam kullanma.

Neler öğreneceksiniz?

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

Yapacaklarınız

  • Uyku kalitesi verilerini göstermek üzere RecyclerView kullanmak için önceki dersteki TrackMySleepquality uygulamasını değiştirin.

Bu codelab'de, uygulamanın uyku kalitesini izleyen RecyclerView bölümünü derlersiniz. Uygulama, uyku verilerini zaman içinde depolamak için bir Room veritabanı kullanır.

Başlangıçtaki uyku izleyici uygulamasında, 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. 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ğ tarafta gösterilen ikinci ekran uyku kalitesi puanı seçmek içindir.

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

İlk ekranda görüntülenen uyku geceleri listesi işlevsel olsa da pek hoş değildir. Uygulama, metin görünümü için metin dizeleri ve kaliteye yönelik sayılar oluşturmak için karmaşık bir biçimlendirici kullanır. Ayrıca, bu tasarım ölçeklendirilmez. Bu codelab'de tüm bu sorunları düzelttikten sonra nihai uygulama aynı işleve sahip olur ve ana ekran şu şekilde görünür:

Bir liste veya veri tablosu görüntülemek, Android'de en yaygın kullanıcı arayüzü görevlerinden biridir. Listeler basitten çok karmaşıka kadar farklılık gösterir. Metin görüntülemeleri listesinde, alışveriş listesi gibi basit veriler gösterilebilir. Karmaşık bir liste (ör. tatil için takip edilen yerler listesi) kullanıcıya kaydırmalı bir tablo içinde başlık içeren birçok ayrıntı gösterebilir.

Tüm bu kullanım alanlarını desteklemek için Android, RecyclerView widget'ını sağlar.

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

  • Varsayılan olarak, RecyclerView yalnızca şu anda ekranda görünen öğeleri işlemek veya çizmek için çalışır. Örneğin, listenizde bin öğe varsa ancak yalnızca 10 öğe gösteriliyorsa RecyclerView ekranda 10 öğe çizmek için yalnızca yeterli işlemi yapar. Kullanıcı sayfayı kaydırdığında RecyclerView ekranda hangi yeni öğelerin olması gerektiğini anlar ve bu öğeleri görüntülemek için yeterli çabayı gösterir.
  • Bir öğe ekranın dışına kaydırıldığında öğenin görünümleri geri dönüştürülür. Bu, öğenin ekrana kaydıran yeni içerikle doldurulduğu anlamına gelir. Bu RecyclerView davranışı, çok fazla işlem süresi kazandırır ve listelerin değişken şekilde kaydırılmasına yardımcı olur.
  • Bir öğe değiştiğinde, listenin tamamını yeniden çizmek yerine RecyclerView söz konusu öğeyi güncelleyebilir. Bu, karmaşık öğelerin listelerini görüntülerken büyük bir verimlilik artışı sağlar.

Aşağıda gösterilen sırayla, bir görünümün (ABC) verilerle doldurulduğunu görebilirsiniz. Bu görünüm ekranın dışına kaydırıldıktan sonra RecyclerView, yeni veriler için (XYZ) görünümü yeniden kullanır.

Adaptör deseni

Farklı elektrik prizleri kullanan ülkeler arasında seyahat ederseniz adaptör kullanarak cihazlarınızı prizlere nasıl bağlayacağınızı biliyorsunuz. Bağdaştırıcı, bir tür fişi bir başkasına dönüştürmenizi sağlar. Bu da bir arayüzü başka bir arayüze dönüştürür.

Yazılım mühendisliğindeki uyarlayıcı kalıbı, bir nesnenin başka bir API ile çalışmasına yardımcı olur. RecyclerView, uygulama verilerini RecyclerView Uyku izleyici uygulaması için, Room veritabanındaki verileri ViewModel özelliğini değiştirmeden RecyclerView tarafından nasıl görüntüleneceğini bildiği bir şeye uyarlayan bir adaptör oluşturursunuz.

RecyclerView uygulama

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

  • Gösterilecek veriler.
  • Görüntülemeler için kapsayıcı görevi görmek üzere düzen dosyanızda tanımlanan bir RecyclerView örneği.
  • Tek bir veri öğesinin düzeni.
    Tüm liste öğeleri aynı görünüyorsa tüm öğeler için aynı düzeni kullanabilirsiniz ancak bu zorunlu değildir. Her defasında bir öğe görünümünün verilerle doldurulabilmesi için öğe düzeninin parçanın düzeninden ayrı olarak oluşturulması gerekir.
  • Düzen yöneticisi.
    Düzen yöneticisi, bir görünümdeki kullanıcı arayüzü bileşenlerinin düzenini (düzenini) yönetir.
  • Bir görünüm sahibi.
    Görünüm sahibi, ViewHolder sınıfını genişletir. Öğenin düzeninden bir öğeyi görüntülemek için görüntüleme bilgilerini içerir. Görünüm sahipleri, RecyclerView adlı kullanıcının görünümü etkili şekilde taşımak için kullandığı bilgileri de ekler.
  • Adaptör.
    Bağdaştırıcı, verilerinizi RecyclerView hizmetine bağlar. Verileri ViewHolder içinde görüntülenebilecek şekilde uyarlar. RecyclerView, verilerin ekranda nasıl görüntüleneceğini öğrenmek için adaptörü kullanır.

Bu görevde düzen dosyanıza bir RecyclerView ekler ve RecyclerView verilerini uyku verilerine göstermek için bir Adapter ayarlarsınız.

1. Adım: LayoutManager ile RecyclerView'u ekleme

Bu adımda, fragment_sleep_tracker.xml dosyasındaki ScrollView öğesini RecyclerView ile değiştirirsiniz.

  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 öğelerini de siler.
  5. Palet bölmesinde, sol taraftaki bileşen türleri listesinde gezinerek Kapsayıcılar'ı bulun ve seçin.
  6. Palet bölmesinden bir RecyclerView bileşenini Bileşen Ağacı bölmesine sürükleyin. RecyclerView öğesini ConstraintLayout öğesinin 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ısını Gradle dosyanıza eklemesine izin vermek için Tamam'ı tıklayın. Bu işlem birkaç saniye sürebilir ve uygulamanız senkronize edilir.

  1. Modül build.gradle dosyasını açın, sonuna gidin ve aşağıdaki koda benzer şekilde görünen yeni bağımlılığı not edin:
implementation 'androidx.recyclerview:recyclerview:1.0.0'
  1. fragment_sleep_tracker.xml uygulamasına geri dön.
  2. Text (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. sleep_list için RecyclerView id verin.
android:id="@+id/sleep_list"
  1. ConstraintLayout içinde RecyclerView, ekranın kalan kısmını kaplayacak şekilde konumlandırın. Bunu yapmak için RecyclerView öğesinin üst kısmını Başlat düğmesine, en alttaki Temizle düğmesine ve her bir tarafı üst öğeye yerleştirin. Aşağıdaki kodu kullanarak Düzen Düzenleyici'de veya XML'de 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'ye bir düzen yöneticisi ekleyin. Her RecyclerView, listedeki öğelerin nasıl konumlanacağını belirten bir düzen yöneticisine ihtiyaç duyar. Android, varsayılan olarak öğeleri tam genişlikli satırlardan oluşan dikey bir listeye yerleştiren bir LinearLayoutManager sağlar.
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
  1. Tasarım sekmesine geçin. Eklenen kısıtlamaların mevcut alanı dolduracak şekilde RecyclerView genişlemesine neden olduğunu fark edin.

2. Adım: Liste öğesi düzenini ve metin görünümü sahibini 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 ürününe mümkün olduğunca hızlı bir şekilde ulaşmak için ilk olarak yalnızca uyku kalitesini sayı olarak gösteren basit bir liste öğesi kullanırsınız. Bunun için bir görünüm sahibine (TextItemViewHolder) ihtiyacınız var. Ayrıca veriler için bir görünüme (TextView) ihtiyacınız vardır. (Daha sonraki bir adımda, görüntüleme sahipleri ve tüm uyku verilerini ayarlama 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 uygulamasında verilen tüm kodu silin.
  3. Başında ve sonunda 16dp dolgu bulunan bir TextView ve metin boyutu 24sp ekleyin. Genişlikle üst öğe eşleşmelidir ve yükseklik, içeriği sarmalar. Bu görünüm RecyclerView içinde görüntülendiğinden, bir 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'yi açın. Sona ilerleyin ve aşağıda gösterilen tanımı ekleyin. Bu, TextItemViewHolder sınıfını oluşturur. Kodu, dosyanın en altına, son kapanış ayracından sonra yerleştirin. Bu görünüm sahibi geçici olduğu ve kodu daha sonra değiştirdiğiniz için kod Util.kt olarak girilir.
class TextItemViewHolder(val textView: TextView): RecyclerView.ViewHolder(textView)
  1. İstenirse android.widget.TextView ve androidx.recyclerview.widget.RecyclerView içe aktarın.

3. Adım: SleepNightAdapter oluşturun

Bir RecyclerView uygulamanın temel görevi, adaptörü oluşturmaktır. Öğe görünümü için basit bir görünüm sahibiniz ve her öğe için bir düzeniniz vardır. Artık bir adaptör oluşturabilirsiniz. Adaptör, bir görünüm sahibi oluşturur ve RecyclerView öğesinin görüntülenmesi için bu veri ve dolguyu doldurur.

  1. sleeptracker paketinde SleepNightAdapter adlı yeni bir Kotlin sınıfı oluşturun.
  2. SleepNightAdapter sınıfının RecyclerView.Adapter olmasını sağlayın. SleepNight nesnesi, RecyclerView tarafından kullanılabilecek şekilde uyarlandığı için sınıfa SleepNightAdapter adı verilir. Bağdaştırıcının hangi görüntüleme sahibinin kullanılacağını bilmesi gerektiğinden TextItemViewHolder içinde iletmeniz gerekir. İstendiğinde gerekli bileşenleri içe aktardığınızda uygulanması gereken zorunlu yöntemler olduğu için bir hata mesajı görürsünüz.
class SleepNightAdapter: RecyclerView.Adapter<TextItemViewHolder>() {}
  1. Verileri muhafazaya almak için SleepNightAdapter üst düzeyinde bir listOf SleepNight değişkeni oluşturun.
var data =  listOf<SleepNight>()
  1. SleepNightAdapter içinde, data içindeki uyku geceleri listesinin boyutunu döndürmek için getItemCount() değerini geçersiz kılın. RecyclerView, adaptörün kaç öğeyi görüntüleyebileceğini bilmelidir ve bunu getItemCount() çağırarak yapar.
override fun getItemCount() = data.size
  1. SleepNightAdapter uygulamasında onBindViewHolder() işlevini aşağıda gösterildiği gibi 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. Dolayısıyla, onBindViewHolder() yöntemi iki bağımsız değişken alır: bir görünüm sahibi ve verilerin bağlanacağı konum. Bu uygulama için sahip, TextItemViewHolder ve konum listedeki konumdur.
override fun onBindViewHolder(holder: TextItemViewHolder, position: Int) {
}
  1. onBindViewHolder() içinde, verideki belirli bir konumdaki bir öğe için değişken oluşturun.
 val item = data[position]
  1. Oluşturduğunuz ViewHolder, textView adlı bir özelliğe sahip. onBindViewHolder() içinde textView text öğesini uyku kalitesi numarasına ayarlayın. Bu kodda yalnızca numaraların listesi gösterilir. Ancak bu basit örnek, bağdaştırıcının verileri görünüm sahibine ve ekrana nasıl getirdiğini görmenizi sağlar.
holder.textView.text = item.sleepQuality.toString()
  1. SleepNightAdapter içinde onCreateViewHolder() öğesini geçersiz kılın ve uygulayın. Bu işlem, RecyclerView bir öğeyi temsil etmek için görünüm sahibine ihtiyaç duyduğunda çağrılır.

    Bu işlev iki parametre alır ve ViewHolder döndürür. Görünüm sahibini içeren görüntüleme grubu olan parent parametresi her zaman RecyclerView değeridir. viewType parametresi, aynı RecyclerView içinde birden çok görünüm olduğunda kullanılır. Örneğin, aynı RecyclerView içinde metin görüntülemeleri, resim ve video listelerini yerleştirirseniz onCreateViewHolder() işlevinin ne tür bir görünüm kullanacağını bilmesi gerekir.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TextItemViewHolder {
}
  1. onCreateViewHolder() içinde LayoutInflater örneğini oluşturun.

    Düzenleyici, XML düzenlerinden nasıl görünüm oluşturacağınızı bilir. context, görünümün doğru şekilde nasıl yükseltileceğiyle ilgili bilgiler içerir. Geri dönüşüm görünümü için bir adaptörde parent görünüm grubu (RecyclerView) bağlamında her zaman geçiş yaparsınız.
val layoutInflater = LayoutInflater.from(parent.context)
  1. onCreateViewHolder() içinde, layoutinflater adlı kişiden şişirmeyi 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ü Boole bağımsız değişkeni attachToRoot. Bu bağımsız değişkenin false olması gerekir. Çünkü RecyclerView, zamanı geldiğinde bu öğeyi sizin için görüntüleme hiyerarşisine ekler.
val view = layoutInflater
       .inflate(R.layout.text_item_view, parent, false) as TextView
  1. onCreateViewHolder() içinde, view ile yapılmış bir TextItemViewHolder döndürün.
return TextItemViewHolder(view)
  1. RecyclerView veriler hakkında bilgi sahibi olmadığı için adaptörün data değiştiğinde RecyclerView öğesini bilgilendirmesi gerekir. Yalnızca bağdaştırıcının ona verdiği görüntüleme sahiplerini bilir.

    Gösterdiği veriler değiştiğinde RecyclerView adlı kullanıcıya bildirmek için SleepNightAdapter sınıfının en üstündeki data değişkenine özel bir değiştirici ekleyin. Ayarlayıcıda, data için yeni bir değer belirleyin, ardından listeyi yeni verilerle yeniden tetiklemeyi tetiklemek için notifyDataSetChanged() numarasını arayın.
var data =  listOf<SleepNight>()
   set(value) {
       field = value
       notifyDataSetChanged()
   }

4. Adım: RecyclerView'dan Bağdaştırıcı hakkında bilgi verin

RecyclerView, görünüm sahiplerini almak için kullanılacak adaptör hakkında bilgi sahibi olmalıdır.

  1. SleepTrackerFragment.kt'yi açın.
  2. onCreateview() bölgesinde bir adaptör oluşturun. Bu kodu, ViewModel modelinin oluşturulmasından sonra ve return ifadesinden önce yerleştirin.
val adapter = SleepNightAdapter()
  1. adapter, RecyclerView ile 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 > Önbellekleri Geçersiz Kıl / Yeniden Başlat'ı seçin.)

    Uygulamayı şimdi çalıştırırsanız herhangi bir hata oluşmaz, ancak Başlat'a ve ardından Durdur'a dokunduğunuzda görüntülenen hiçbir veri görmezsiniz.

5. Adım: Verileri bağdaştırıcıya aktarın

Şu ana kadar bir adaptör ve bağdaştırıcıdan verileri RecyclerView almanın bir yolu var. Şimdi ViewModel kaynağından adaptöre veri almanız gerekiyor.

  1. SleepTrackerViewModel'yi açın.
  2. Tüm uyku gecelerini depolayacak nights değişkenini bulun. nights değişkeni, veritabanında getAllNights() çağrısı yapılarak ayarlanır.
  3. Bu değişkene erişmesi gereken bir gözlemci oluşturacağınız için private öğesini nights öğesinden kaldırın. Beyanınız aşağıdaki gibi görünmelidir:
val nights = database.getAllNights()
  1. database paketinde SleepDatabaseDao öğesini açın.
  2. getAllNights() işlevini bulun. Bu işlevin, SleepNight değerleri listesini LiveData olarak döndürdüğüne dikkat edin. Yani nights değişkeni, Room tarafından güncellenen LiveData değerini içerir ve ne zaman değiştiğini öğrenmek için nights değerini gözlemleyebilirsiniz.
  3. SleepTrackerFragment'yi açın.
  4. onCreateView() içinde, adapter değerinin oluşturulmasının altında nights değişkeninde bir gözlemci oluşturun.

    Ömür boyu sahip olarak parçanın viewLifecycleOwner özelliğini sağlayarak bu gözlemcinin yalnızca RecyclerView ekranda olduğunda etkin olmasını sağlayabilirsiniz.
sleepTrackerViewModel.nights.observe(viewLifecycleOwner, Observer {
   })
  1. Gözlemcinin içinde, null olmayan bir değer (nights için) her aldığınızda değeri adaptöre data atayın. Bu, gözlemleyen için tamamlanmış koddur ve verileri ayarlar:
sleepTrackerViewModel.nights.observe(viewLifecycleOwner, Observer {
   it?.let {
       adapter.data = it
   }
})
  1. Kodunuzu oluşturun ve çalıştırın.

    Adaptörünüz çalışıyorsa uyku kalitesi numaralarını liste olarak görürsünüz. Soldaki ekran görüntüsünde Başlat'a dokunduğunuzda -1 değeri gösterilir. Sağ taraftaki ekran görüntüsünde, Durdur'a dokunup kalite puanı seçtikten sonra, güncellenen uyku kalitesi numarası gösterilir.

6. Adım: Görüntüleme sahiplerinin nasıl geri dönüştürüldüğünü keşfedin

RecyclerView, görünüm sahiplerini geri dönüştürür. Bu durumda, kartları yeniden kullanır. Bir görünüm ekranın dışına kaydırıldığında RecyclerView, ekrana kaydırmak üzere olan görünümün görünümünü yeniden kullanır.

Bu görüntüleme sahipleri geri dönüştürüldüğünden, onBindViewHolder()'in önceki öğelerin bir görünüm sahibi üzerinde ayarlamış olabileceği özelleştirmeleri ayarladığından veya sıfırladığından emin olun.

Örneğin, kalite puanları 1'den küçük veya 1'e eşit olan ve kötü uykuyu temsil eden görüntüleme sahiplerinde metin rengini kırmızı olarak ayarlayabilirsiniz.

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

    RecyclerView, görünüm sahiplerini yeniden kullandığında sonuçta yüksek kaliteli bir puan için kırmızı görüntüleme sahiplerinden birini yeniden kullanır. Yüksek derecelendirme yanlışlıkla kırmızı renkte gösterilir.

  1. Bunu düzeltmek için renk kalitesinden küçük veya eşit değilse rengi siyah olarak ayarlamak için bir else ifadesi ekleyin.

    Her iki koşul da açık olduğunda görünüm sahibi 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ın her zaman doğru renge sahip olması gerekir.

Tebrikler! Artık tamamen işlevsel bir RecyclerView sürümüne sahipsiniz.

Bu görevde basit görünüm sahibini uyku gecesi için daha fazla veri gösterebilecek bir kişi ile değiştirirsiniz.

Util.kt öğesine eklediğiniz basit ViewHolder, bir TextItemViewHolder içinde TextView öğesini sarmalar.

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

RecyclerView, neden doğrudan TextView kullanmıyor? Bu tek kod satırı birçok işlev sağlıyor. ViewHolder, bir öğenin görünümünü ve RecyclerView içindeki konumuyla ilgili meta verileri açıklar. RecyclerView, liste kaydırılırken görünümü doğru şekilde konumlandırmak ve Adapter öğesinde öğeler eklendiğinde veya kaldırıldığında animasyon görünümleri gibi ilginç şeyler yapmak için bu işlevi kullanır.

RecyclerView ürününün, ViewHolder içinde depolanan görünümlere erişmesi gerekiyorsa bunu görünüm sahibinin itemView özelliğini kullanarak yapabilirsiniz. RecyclerView, bir öğeyi ekranda görüntülenecek bir bağlama yaparken, kenarlık gibi bir görünümün etrafına çizim yaparken ve erişilebilirliği uygularken itemView kullanır.

1. Adım: Öğe düzenini oluşturun

Bu adımda, bir öğe için düzen dosyasını oluşturursunuz. Düzen, uyku kalitesi için ImageView, uyku uzunluğu için TextView ve metin olarak kalite için TextView içeren bir ConstraintLayout içerir. Daha önce düzenleri oluşturduğunuz için sağlanan XML kodunu kopyalayıp yapıştırın.

  1. Yeni bir düzen kaynağı dosyası oluşturun ve dosyaya list_item_sleep_night adını verin.
  2. Dosyadaki kodun tamamını aşağıdaki kodla değiştirin. Ardından, oluşturduğunuz düzen hakkında bilgi edinin.
<?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 ekran görüntüsünde yer alır. Şema görünümündeyken sağ taraftaki ekran görüntüsüne benzer.

2. Adım: ViewHolder oluşturun

  1. SleepNightAdapter.kt'yi açın.
  2. SleepNightAdapter içinde ViewHolder adlı bir sınıf oluşturun ve RecyclerView.ViewHolder süresini uzatın.
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){}
  1. ViewHolder içindeki görüntülemeler için referanslar alın. Bu ViewHolder öğesinin güncelleyeceği görünümler için bir referansa ihtiyacınız var. Bu ViewHolder özelliğini her bağladığınızda, resme ve her iki metin görünümüne erişmeniz gerekir. (Bu kodu daha sonra veri bağlamayı kullanmak için dönüştürürsiniz.)
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: SleepNightAdapter'da ViewHolder'ı kullanın

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

onCreateViewHolder() uygulamasını güncelleyin:

  1. ViewHolder özelliğini döndürmek için onCreateViewHolder() imzasını değiştirin.
  2. list_item_sleep_night olan düzen düzenini kullanmak için düzen şişiriciyi değiştirin.
  3. TextView adlı oyuncuyu kaldır.
  4. TextItemViewHolder değeri yerine bir ViewHolder döndürün.

    Burada tamamlanmış son onCreateViewHolder() işlevi verilmiştir:
    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() uygulamasını güncelleyin:

  1. onBindViewHolder() öğesinin 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 veren 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. Aşağıdaki kodu kopyalayın. Bu ad, başlangıç koduyla sağlanan bir biçimlendirme işlevini çağırır.
holder.sleepLength.text = convertDurationToFormatted(item.startTimeMilli, item.endTimeMilli, res)
  1. Bu, convertDurationToFormatted() öğesinin tanımlanması gerektiğinden bir hata verir. Util.kt uygulamasını açın ve kodla ilişkili kodu ve ilişkili içe aktarma işlemlerini iptal edin. (Kod > Satır Yorumları ile Yorum'u seçin.)
  2. Kaliteyi ayarlamak için onBindViewHolder() değerini 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. Yeni ic_sleep_active simgesi, başlangıç kodu içinde sunulur.
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. ViewHolder için tüm verileri ayarlayarak, güncellenen güncellenmiş onBindViewHolder() işlevini burada bulabilirsiniz:
   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, uyku kalitesi simgesini ve uyku kalitesi ile uyku kalitesini gösteren aşağıdaki ekran görüntüsüne benzemelidir.

RecyclerView cihazınız artık tamamlandı. Bir Adapter ve ViewHolder yapmayı öğrendiniz ve RecyclerView Adapter içeren bir liste görüntülemek için bunları bir araya getirdiniz.

Şimdiye kadar kodunuz, adaptör oluşturma ve görüntüleme sahibi işlemini gösterir. Ancak bu kodu daha iyi hale getirebilirsiniz. Gösterilecek kod ve görüntüleme sahiplerini yönetme kodu karışıktır ve onBindViewHolder(), ViewHolder öğesinin nasıl güncelleneceğine dair ayrıntıları bilir.

Üretim uygulamasında birden fazla görüntüleme sahibi, daha karmaşık bağdaştırıcılar ve değişiklik yapan birden fazla geliştirici olabilir. Kodunuzu, bir görünüm sahibiyle ilgili her şeyin yalnızca görünüm sahibi içinde olacağı şekilde yapılandırmanız gerekir.

1. Adım: onConnectViewHolder() parametresini yeniden düzenleyin

Bu adımda kodu yeniden düzenler ve tüm görüntüleme sahibi işlevlerini ViewHolder ürününe taşırsı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ı daha kolay ve daha güvenli hale getirmektir. Neyse ki Android Studio'nun size yardımcı olacak araçları var.

  1. SleepNightAdapter öğesinde onBindViewHolder() değişkenini item tanımlaması için ifade hariç her şeyi seçin.
  2. Sağ tıklayıp Yeniden Düzenleme > Ayıklama > İşlevi'ni seçin.
  3. İşleve bind adını verin ve önerilen parametreleri kabul edin. Tamam'ı tıklayın.

    bind() işlevi onBindViewHolder() 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() öğesinin holder parametresinin holder kelimesine getirin. Niyet menüsünü 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 içine yapıştırın.
  2. bind() adlı yeri herkese açık hale getirin.
  3. Gerekirse bind() adaptörüne aktarın.
  4. Şu anda ViewHolder bölümünde olduğundan imzanın ViewHolder kısmı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 için yeniden düzenleme

Adaptördeki onCreateViewHolder() yöntemi şu anda ViewHolder için düzen kaynağından görünümü şişiriyor. Ancak, adaptörle ve ViewHolder ile ilgili her şeyin şişmeyle ilgisi yoktur. ViewHolder içinde enflasyon oluşmalıdır.

  1. onCreateViewHolder() içinde işlevin gövdesindeki tüm kodu seçin.
  2. Sağ tıklayıp Yeniden Düzenleme > Ayıklama > İşlevi'ni seçin.
  3. İşleve from adını verin ve önerilen parametreleri kabul edin. Tamam'ı tıklayın.
  4. İmleci from adlı işlev adının üzerine getirin. Niyet menüsünü açmak için Alt+Enter (Mac'te Option+Enter) tuşuna basın.
  5. Tamamlayıcı nesneye taşı'yı seçin. from() işlevinin, ViewHolder örneğinde değil, ViewHolder sınıfında çağrılabilmesi için bir tamamlayıcı nesnesinde olması gerekir.
  6. companion nesnesini ViewHolder sınıfına taşıyın.
  7. from() adlı yeri herkese açık hale getirin.
  8. onCreateViewHolder() içinde, return ifadesini ViewHolder sınıfında from() çağırma sonucunu döndürecek şekilde değiştirin.

    Tamamladığınız onCreateViewHolder() ve from() yöntemleriniz aşağıdaki koda benzeyecek şekilde olmalı ve kodunuz hatasız olarak oluşturulmalı ve ç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. Oluşturanın gizli olması için ViewHolder sınıfının imzasını değiştirin. from() artık yeni bir ViewHolder örneği döndüren bir yöntem olduğu için artık ViewHolder ürününün kurucusunu çağırmanın bir nedeni yok.
class ViewHolder private constructor(itemView: View) : RecyclerView.ViewHolder(itemView){
  1. Uygulamayı çalıştırın. Uygulamanız, aynı şekilde derlenip çalıştırılmalıdır. Bu işlem, yeniden bakımdan sonra istenen sonuçtur.

Android Studio projesi: RecyclerViewFundamentals

  • Bir liste veya veri tablosu görüntülemek, Android'de en yaygın kullanıcı arayüzü görevlerinden biridir. RecyclerView, çok büyük listeler görüntülerken bile verimli olacak şekilde tasarlanmıştır.
  • RecyclerView yalnızca şu anda ekranda görünen öğeleri işlemek veya çizmek için gereken işi yapar.
  • Bir öğe ekranın dışına kaydırıldığında görünümleri geri dönüştürülmüş hale gelir. Bu, öğenin ekrana kaydıran yeni içerikle doldurulduğu anlamına gelir.
  • Yazılım mühendisliğindeki uyarlayıcı kalıbı, bir nesnenin başka bir API ile birlikte çalışmasına yardımcı olur. RecyclerView, uygulama verilerini depolayabileceği ve işlemesine gerek kalmadan uygulama verilerini gösterebileceği bir şeye dönüştürmek için bir adaptör kullanır.

RecyclerView uygulamasında verilerinizi 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 bir <RecyclerView> öğesi tanımlayın.
  • LayoutManager
    RecyclerView, RecyclerView içindeki öğelerin düzenini düzenlemek için LayoutManager kullanır. Örneğin, bunları bir ızgaraya veya doğrusal bir listeye yerleştirmek gibi.

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

    Ayrıca, LayoutManager için RecyclerView öğesini programatik olarak da ayarlayabilirsiniz. (Bu teknik daha sonraki bir codelab'de ele alınmıştır.)
  • Her öğe için düzen
    Bir XML düzeni dosyasındaki bir öğe öğesi için düzen oluşturun.
  • Bağdaştırıcı
    Verileri ve ViewHolder içinde nasıl görüntüleneceğini hazırlayan bir bağdaştırıcı oluşturun. Adaptörü RecyclerView ile ilişkilendirin.

    RecyclerView çalıştırıldığında adaptörü kullanarak verilerin ekranda nasıl görüntüleneceğini öğrenmek için bu adaptörü kullanır.

    Adaptör, aşağıdaki yöntemleri uygulamanızı gerektirir:
    - öğe sayısını döndürmek için getItemCount().
    -onCreateViewHolder() bir öğenin ViewHolder değerini döndürmek için.
    onBindViewHolder() listedeki verileri bir öğenin görüntüleme sayısına uyarlamak için.

  • ViewHolder
    ViewHolder, öğenin düzenindeki bir öğenin gösterilmesini sağlayan 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 artırır ve verileri düzendeki görünümlere yerleştirir.
  • RecyclerView verileri hakkında bilgi sahibi olmadığından, Adapter bu veriler değiştiğinde RecyclerView hakkında bilgi vermelidir. Verilerin değiştiğini Adapter bildirmek için notifyDataSetChanged() kullanın.

Udacity kursu:

Android geliştirici dokümanları:

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

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

▢ Öğeleri bir listede veya ızgarada görüntüler.

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

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

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

2. Soru

RecyclerView kullanmanın avantajları nelerdir? Geçerli 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 açılan bir sonraki öğeyi görüntülemek için ekranın dışına kaydırılan görünümü yeniden kullanır.

3. Soru

Adaptörleri kullanmanın nedenlerinden bazıları nelerdir? Geçerli olan tüm seçenekleri işaretleyin.

arasındaki endişelerin birbirinden ayrılması, kodu değiştirmeyi ve test etmeyi kolaylaştırır.

RecyclerView, gösterilen verilerden bağımsız.

▢ Veri işleme katmanlarının, verilerin nasıl görüntüleneceğiyle ilgili endişe duymaları gerekmez.

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

4. Soru

ViewHolder ile ilgili olarak aşağıdakilerden hangisi doğrudur? Geçerli olan tüm seçenekleri işaretleyin.

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

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

RecyclerView ile birden fazla ViewHolder ekleyebilirsiniz.

Adapter, verileri ViewHolder hizmetine bağlar.

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