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
ileAdapter
veViewHolder
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 durumdaysaRecyclerView
, ekranda 10 öğe çizmek için yeterli miktarda işlem yapar. Kullanıcı kaydırdığındaRecyclerView
, 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ı, verileriniziRecyclerView
'ye bağlar. VerileriViewHolder
içinde görüntülenebilecek şekilde uyarlar. BirRecyclerView
, 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.
- GitHub'dan RecyclerViewFundamentals-Starter uygulamasını indirin.
- Uygulamayı oluşturup çalıştırın. Verilerin nasıl basit metin olarak gösterildiğine dikkat edin.
- Android Studio'daki Tasarım sekmesinde
fragment_sleep_tracker.xml
düzen dosyasını açın. - Bileşen Ağacı bölmesinde
ScrollView
öğesini silin. Bu işlem,ScrollView
içindekiTextView
öğesini de siler. - Palet bölmesinde, soldaki bileşen türleri listesinde Kapsayıcılar'ı bulup seçin.
RecyclerView
simgesini Palet bölmesinden Bileşen Ağacı bölmesine sürükleyin.RecyclerView
cihazınıConstraintLayout
içine yerleştirin.
- 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.
- 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'
fragment_sleep_tracker.xml
'a geri dönün.- Metin sekmesinde, aşağıda gösterilen
RecyclerView
kodunu bulun:
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent" />
RecyclerView
içinid
sleep_list
verin.
android:id="@+id/sleep_list"
RecyclerView
simgesini,ConstraintLayout
simgesinin içindeki ekranın kalan kısmını kaplayacak şekilde konumlandırın. Bunu yapmak içinRecyclerView
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"
RecyclerView
XML'sine bir düzen yöneticisi ekleyin. HerRecyclerView
, 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 birLinearLayoutManager
sağlar.
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
- 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.)
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.text_item_view.xml
bölümünde, verilen tüm kodu silin.- Başında ve sonunda
16dp
dolgusu olan birTextView
ekleyin ve metin boyutunu24sp
olarak ayarlayın. Genişlik üst öğeyle eşleşsin, yükseklik ise içeriği sarsın. Bu görünümRecyclerView
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" />
Util.kt
adlı kişiyi aç. En sona gidin veTextItemViewHolder
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 kodUtil.kt
içine yerleştirilir.
class TextItemViewHolder(val textView: TextView): RecyclerView.ViewHolder(textView)
- İstenirse
android.widget.TextView
veandroidx.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.
sleeptracker
paketindeSleepNightAdapter
adlı yeni bir Kotlin sınıfı oluşturun.SleepNightAdapter
sınıfınıRecyclerView.Adapter
sınıfını genişletecek şekilde oluşturun. Bu sınıfaSleepNightAdapter
adı verilir. ÇünküSleepNight
nesnesiniRecyclerView
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>() {}
SleepNightAdapter
'nın en üst düzeyinde, verileri tutmak için birlistOf
SleepNight
değişkeni oluşturun.
var data = listOf<SleepNight>()
SleepNightAdapter
içinde,data
'deki uyku geceleri listesinin boyutunu döndürmek içingetItemCount()
değerini geçersiz kılın.RecyclerView
, görüntüleyeceği öğe sayısını bilmelidir. Bunu dagetItemCount()
işlevini çağırarak yapar.
override fun getItemCount() = data.size
SleepNightAdapter
içinde, aşağıda gösterildiği gibionBindViewHolder()
işlevini geçersiz kılın.onBindViewHolder()
işlevi, belirtilen konumdaki bir liste öğesinin verilerini görüntülemek içinRecyclerView
tarafından çağrılır. Bu nedenleonBindViewHolder()
yöntemi iki bağımsız değişken alır: görünüm tutucu ve bağlanacak verilerin konumu. Bu uygulamada, kart sahibiTextItemViewHolder
, konum ise listedeki konumdur.
override fun onBindViewHolder(holder: TextItemViewHolder, position: Int) {
}
onBindViewHolder()
içinde, verilerde belirli bir konumdaki bir öğe için değişken oluşturun.
val item = data[position]
- Oluşturduğunuz
ViewHolder
,textView
adlı bir mülke sahip.onBindViewHolder()
içinde,textView
öğesinintext
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()
SleepNightAdapter
içinde,RecyclerView
bir öğeyi temsil etmek için görünüm tutucuya ihtiyaç duyduğunda çağrılanonCreateViewHolder()
işlevini geçersiz kılın ve uygulayın.
Bu işlev iki parametre alır veViewHolder
döndürür. Görünüm tutucuyu barındıran görünüm grubu olanparent
parametresi her zamanRecyclerView
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ştirirsenizonCreateViewHolder()
işlevinin hangi tür görünümü kullanacağını bilmesi gerekir.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TextItemViewHolder {
}
onCreateViewHolder()
içindeLayoutInflater
ö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 zamanparent
görünüm grubunun bağlamını (RecyclerView
) iletirsiniz.
val layoutInflater = LayoutInflater.from(parent.context)
onCreateViewHolder()
içinde,layoutinflater
'danview
şişirmesini isteyerekview
oluşturun.
Görünüm için XML düzenini ve görünüm içinparent
görünüm grubunu iletin. Üçüncü bağımsız değişken olan boole bağımsız değişkeniattachToRoot
'dır. Bu bağımsız değişkenfalse
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
onCreateViewHolder()
içindeview
ile oluşturulanTextItemViewHolder
değerini döndürün.
return TextItemViewHolder(view)
RecyclerView
, veriler hakkında hiçbir şey bilmediğindendata
değiştiğinde bağdaştırıcınınRecyclerView
'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ğindeRecyclerView
öğesine bilgi vermek içinSleepNightAdapter
sınıfının en üstündekidata
değişkenine özel bir ayarlayıcı ekleyin. Ayarlayıcıdadata
için yeni bir değer verin, ardındannotifyDataSetChanged()
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.
SleepTrackerFragment.kt
adlı kişiyi aç.onCreateview()
içinde bir bağdaştırıcı oluşturun. Bu kodu,ViewModel
modeli oluşturulduktan sonra vereturn
ifadesinden önce yerleştirin.
val adapter = SleepNightAdapter()
adapter
ileRecyclerView
'yi ilişkilendirin.
binding.sleepList.adapter = adapter
binding
nesnesini güncellemek için projenizi temizleyip yeniden oluşturun.binding.sleepList
veyabinding.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.
SleepTrackerViewModel
adlı kişiyi aç.- Gösterilecek veriler olan tüm uyku gecelerini depolayan
nights
değişkenini bulun.nights
değişkeni, veritabanındagetAllNights()
çağrılarak ayarlanır. - Bu değişkene erişmesi gereken bir gözlemci oluşturacağınız için
private
değişkenininights
öğesinden kaldırın. Beyanınız aşağıdaki gibi görünmelidir:
val nights = database.getAllNights()
database
paketindeSleepDatabaseDao
dosyasını açın.getAllNights()
işlevini bulun. Bu işlevin,SleepNight
değerlerinin listesiniLiveData
olarak döndürdüğünü unutmayın. Bu,nights
değişkenininRoom
tarafından güncel tutulanLiveData
içerdiği ve ne zaman değiştiğini öğrenmek içinnights
değişkenini gözlemleyebileceğiniz anlamına gelir.SleepTrackerFragment
adlı kişiyi aç.onCreateView()
içinde,adapter
oluşturulduktan sonranights
değişkeninde bir gözlemci oluşturun. ParçanınviewLifecycleOwner
öğesini yaşam döngüsü sahibi olarak sağlayarak bu gözlemcinin yalnızcaRecyclerView
ekrandayken etkin olmasını sağlayabilirsiniz.
sleepTrackerViewModel.nights.observe(viewLifecycleOwner, Observer {
})
- Gözlemcinin içinde, boş olmayan bir değer (
nights
için) aldığınızda değeri bağdaştırıcınındata
öğ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
}
})
- 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.
SleepNightAdapter
sınıfında,onBindViewHolder()
öğesinin sonuna aşağıdaki kodu ekleyin.
if (item.sleepQuality <= 1) {
holder.textView.setTextColor(Color.RED) // red
}
- Uygulamayı çalıştırın.
- Uyku kalitesi düşük veriler eklediğinizde sayı kırmızı olur.
- 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.
- 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
}
- 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.
- Yeni bir düzen kaynak dosyası oluşturun ve dosyayı
list_item_sleep_night
olarak adlandırın. - 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>
- 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
SleepNightAdapter.kt
adlı kişiyi aç.SleepNightAdapter
içindeViewHolder
adlı bir sınıf oluşturun ve bu sınıfıRecyclerView.ViewHolder
olarak genişletin.
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){}
ViewHolder
içinde görünümlere referanslar alın. BuViewHolder
öğesinin güncelleyeceği görünümlere referans vermeniz gerekir. BuViewHolder
öğ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
SleepNightAdapter
tanımındaTextItemViewHolder
yerine yeni oluşturduğunuzSleepNightAdapter.ViewHolder
öğesini kullanın.
class SleepNightAdapter: RecyclerView.Adapter<SleepNightAdapter.ViewHolder>() {
onCreateViewHolder()
adresini güncelleyin:
ViewHolder
değerini döndürmek içinonCreateViewHolder()
işlevinin imzasını değiştirin.- Düzen genişleticiyi doğru düzen kaynağını (
list_item_sleep_night
) kullanacak şekilde değiştirin. TextView
cihazına yayınlama işlemini kaldırın.TextItemViewHolder
yerineViewHolder
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:
onBindViewHolder()
işlevinin imzasını,holder
parametresiTextItemViewHolder
yerineViewHolder
olacak şekilde değiştirin.onBindViewHolder()
içinde,item
tanımı hariç tüm kodu silin.- Bu görünüm için
resources
öğesine referans içeren birval
res
tanımlayın.
val res = holder.itemView.context.resources
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)
- 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.) onBindViewHolder()
'ya geri dönün ve kaliteyi ayarlamak içinconvertNumericQualityToString()
'ı kullanın.
holder.quality.text= convertNumericQualityToString(item.sleepQuality, res)
- Bu işlevleri manuel olarak içe aktarmanız gerekebilir.
import com.example.android.trackmysleepquality.convertDurationToFormatted
import com.example.android.trackmysleepquality.convertNumericQualityToString
- 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
})
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
})
}
- 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.
SleepNightAdapter
bölümünde,onBindViewHolder()
bölümünde, değişkeni bildirmek için kullanılan ifadeitem
dışındaki her şeyi seçin.- Sağ tıklayın, ardından Yeniden düzenle > Ayıkla > İşlev'i seçin.
- İş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
})
}
- İmleci,
bind()
parametresininholder
kelimesinin üzerine getirin.holder
Amacınıza uygun menüyü açmak içinAlt+Enter
(Mac'teOption+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) {...}
bind()
işlevini kesipViewHolder
aralığına yapıştırın.bind()
herkese açık hâle getirin.- Gerekirse
bind()
öğesini adaptöre aktarın. - Artık
ViewHolder
içinde olduğu için imzanınViewHolder
bölümünü kaldırabilirsiniz.ViewHolder
sınıfındakibind()
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.
onCreateViewHolder()
bölümünde, işlevin gövdesindeki tüm kodu seçin.- Sağ tıklayın, ardından Yeniden düzenle > Ayıkla > İşlev'i seçin.
- İşlevi
from
olarak adlandırın ve önerilen parametreleri kabul edin. Tamam'ı tıklayın. - İmleci işlev adının üzerine getirin
from
. Amacınıza uygun menüyü açmak içinAlt+Enter
(Mac'teOption+Enter
) tuşuna basın. - 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. companion
nesnesiniViewHolder
sınıfına taşıyın.from()
herkese açık hâle getirin.onCreateViewHolder()
içinde,return
ifadesiniViewHolder
sınıfındafrom()
çağrısının sonucunu döndürecek şekilde değiştirin.
TamamlanmışonCreateViewHolder()
vefrom()
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)
}
}
ViewHolder
sınıfının imzasını, oluşturucunun özel olacak şekilde değiştirin.from()
artık yeni birViewHolder
örneği döndüren bir yöntem olduğundan kimseninViewHolder
oluşturucusunu çağırmasına gerek kalmadı.
class ViewHolder private constructor(itemView: View) : RecyclerView.ViewHolder(itemView){
- 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
ARecyclerView
,RecyclerView
içindeki öğelerin düzenini (ör. öğeleri bir ızgarada veya doğrusal bir listede düzenleme) organize etmek içinLayoutManager
kullanır.
Düzen dosyasındaki<RecyclerView>
içinde,app:layoutManager
özelliğini düzen yöneticisine (ör.LinearLayoutManager
veyaGridLayoutManager
) ayarlayın.RecyclerView
içinLayoutManager
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 veViewHolder
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çingetItemCount()
.
– Listedeki bir öğeninViewHolder
değerini döndürmek içinonCreateViewHolder()
.
– Listedeki bir öğenin verilerini görünümlere uyarlamak içinonBindViewHolder()
. - ViewHolder
: BirViewHolder
, öğ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. GenellikleonBindViewHolder()
, 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ğindeAdapter
,RecyclerView
'yı bilgilendirmelidir. Verilerin değiştiğiniAdapter
bildirmek içinnotifyDataSetChanged()
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: