Android RecyclerView: Apa itu, Pelajari dengan Contoh Sederhana

Apa yang dimaksud dengan RecyclerView Android?

Tampilan Pendaur Ulang adalah widget yang lebih fleksibel dan versi lanjutan dari GridView dan ListView. Ini adalah wadah untuk menampilkan kumpulan data besar yang dapat digulir secara efisien dengan mempertahankan jumlah tampilan terbatas. Anda dapat menggunakan widget RecyclerView ketika Anda memiliki kumpulan data yang elemennya berubah saat runtime bergantung pada peristiwa jaringan atau tindakan pengguna.

views

Android platform menggunakan kelas View dan ViewGroup untuk menggambar item di layar. Kelas-kelas ini bersifat abstrak dan diperluas ke implementasi berbeda untuk menyesuaikan kasus penggunaan. TextView, misalnya, memiliki tujuan sederhana untuk menampilkan konten teks di layar. EditText diperluas dari kelas View yang sama dan menambahkan lebih banyak fungsi untuk memungkinkan pengguna memasukkan data.

Dimungkinkan untuk membuat tampilan kustom kita sendiri agar dapat mencapai lebih banyak fleksibilitas saat mengembangkan antarmuka pengguna. Kelas View menyediakan metode yang dapat kita ganti untuk menggambar di layar dan sarana untuk meneruskan parameter seperti lebar, tinggi, dan atribut khusus yang ingin kita tambahkan ke View agar berperilaku sesuai keinginan.

LihatGrup

Kelas ViewGroup adalah sejenis View tetapi, tidak seperti kelas View sederhana yang tanggung jawabnya hanya menampilkan, ViewGroup memberi kita kemampuan menempatkan beberapa tampilan ke dalam satu tampilan, yang dapat kita referensikan secara keseluruhan. Dalam hal ini, Tampilan yang dibuat di tingkat atas tempat kita menambahkan tampilan sederhana lainnya (kita juga dapat menambahkan viewGroup) disebut "induk", dan tampilan yang ditambahkan di dalamnya adalah "anak".

Kita dapat menggambarkan View sebagai Array dan ViewGroup sebagai Array dari Array. Mengingat Array dari Array adalah Array itu sendiri, kita dapat melihat bagaimana ViewGroup dapat diperlakukan seperti View.

var arr1 = [1,2,3] //imagine a simple View as an Array
//we can imagine this as a NumberTextView which doesn't really exist
//but we could imagine there's one that makes it easy to use numbers
var arr2 = ["a","b","c"] // We can imagine this as another simple view

var nestedArr = [arr1,arr2] //in our anology, we can now group views 
//together and the structure that would hold that would be what we call the ViewGroup

ViewGroup juga memungkinkan kita untuk menentukan bagaimana anak-anak diatur di dalam tampilan, misalnya, diletakkan secara vertikal atau horizontal. Kita dapat memiliki aturan yang berbeda untuk interaksi di dalam Tampilan. Misalnya, TextView yang mengikuti satu sama lain harus memiliki jarak 12dp sementara ImageView yang diikuti oleh TextView harus memiliki jarak 5dp.

Hal ini akan terjadi jika kita mengembangkan ViewGroup kita sendiri dari awal. Untuk membuat konfigurasi ini lebih mudah, Android menyediakan kelas bernama LayoutParams, yang dapat kita gunakan untuk memasukkan konfigurasi ini.

Android dokumentasi menyediakan beberapa parameter default yang akan kami terapkan saat mengonfigurasi ViewGroup kami sendiri. Beberapa parameter umum adalah parameter yang berkaitan dengan lebar, tinggi, dan margin. Secara default, konfigurasi ini memiliki struktur android:layout_height untuk tinggi, misalnya android:layout_width. Dalam hal ini, saat membuat ViewGroup, Anda selanjutnya dapat membuat LayoutParams khusus sesuai dengan perilaku ViewGroup yang Anda inginkan.

Android hadir dengan Tampilan default dan Grup Tampilan yang dapat kita gunakan untuk melakukan banyak tugas umum yang kita perlukan. Salah satu contoh yang kami sebutkan adalah TextView. Itu adalah tampilan sederhana yang hadir dengan aspek yang dapat dikonfigurasi seperti tinggi, lebar, Ukuran teks, dan sejenisnya. Kami memiliki ImageView untuk menampilkan Gambar dan EditTeks seperti yang telah kami sebutkan, di antara banyak lainnya. Android juga memiliki ViewGroup khusus tempat kita dapat menambahkan Tampilan dan mendapatkan perilaku yang diharapkan.

Tata Letak Linier

LinearLayout memungkinkan kita menambahkan item View di dalamnya. LinearLayout adalah atribut orientasi yang menentukan bagaimana tata letaknya di layar. Ia juga memiliki LinearLayout.LayoutParams yang menentukan aturan untuk tampilan di dalamnya, misalnya, atribut android:center_horizontal akan memusatkan tampilan di sepanjang sumbu horizontal sedangkan, `android:center_vertical akan memusatkan konten tampilan di sepanjang sumbu vertikal.

Berikut beberapa gambar untuk memahami centering. Kami akan menganggap ini sebagai TextView sederhana di dalam ruang 200px kali 200px, atribut pemusatan akan membuatnya berperilaku sebagai berikut.

android:pusat_horizontal

Konten yang Berpusat Secara Horizontal
Konten terpusat secara horizontal

android:pusat_vertikal

Konten yang Berpusat secara vertikal
konten yang terpusat secara vertikal

android:tengah

Konten Terpusat
Konten terpusat

Komponen Inti RecyclerView

Komponen Inti dari RecyclerView
Komponen Inti RecyclerView

Berikut ini adalah komponen penting RecyclerView:

RecyclerView.Adapter

Dasar #1 – Pola Adaptor

Adaptor adalah perangkat yang mengubah atribut sistem atau perangkat menjadi atribut perangkat atau sistem yang tidak kompatibel. Beberapa di antaranya mengubah atribut sinyal atau daya, sementara yang lain hanya menyesuaikan bentuk fisik satu konektor dengan konektor lainnya.

Contoh sederhana yang kita temukan dalam kehidupan nyata untuk menjelaskan Adaptor adalah ketika kita perlu menghubungkan perangkat bersama-sama, tetapi perangkat tersebut memiliki port koneksi yang tidak cocok satu sama lain. Hal ini dapat terjadi jika Anda mengunjungi negara lain yang menggunakan jenis soket berbeda. Jika Anda membawa pengisi daya ponsel atau laptop, mustahil menghubungkannya ke stopkontak. Namun, Anda tidak akan menyerah tetapi cukup mendapatkan Adaptor yang dapat dipasang di antara stopkontak dan pengisi daya Anda dan memungkinkan terjadinya pengisian daya.

Hal ini terjadi dalam pemrograman ketika kita ingin menghubungkan dua struktur data bersama-sama untuk memenuhi tugas, namun port defaultnya tidak memiliki cara untuk berkomunikasi satu sama lain.

Kami akan menggunakan contoh sederhana perangkat dan pengisi daya. Kami akan memiliki dua contoh pengisi daya. Yang Amerika dan yang Inggris

class AmericanCharger() {
    var chargingPower = 10
}
class BritishCharger(){
    var charginPower = 5
}

Kami kemudian akan membuat dua perangkat

class AmericanDevice() 
class BritishDevice()

Sebagai contoh, kita kemudian dapat membuat beberapa contoh perangkat untuk bermain bersama.

var myAmericanPhone = new AmericanDevice()
var myBritishPhone = new BritishDevice()

Kami kemudian akan memperkenalkan konsep pengisian daya untuk kedua perangkat dengan menambahkan metode di perangkat yang disebut charge() .

Metode ini mengambil masukan dari masing-masing pengisi daya dan melakukan pengisian daya berdasarkan pengisi daya tersebut.

sealed trait Device
class AmericanDevice : Device{
    fun charge(charger:AmericanCharger){
        //Do some American charging
    }
}
class BritishDevice: Device{
    fun charge(charger:BritishCharger){
        //Do some British charging
    }
}

Dalam hal ini, berdasarkan analogi kami, karena satu dan lain alasan kami perlu menggunakan BritishCharger saat menggunakan AmericanDevice atau sebaliknya.

Dalam dunia pemrograman, hal ini biasanya terjadi saat menggabungkan perpustakaan yang menawarkan fungsi yang sama (dalam konteks kami, fungsi bersama kami dikenakan biaya). Kita perlu menemukan cara untuk mengaktifkannya.

Jika kita mengikuti analoginya, kita perlu pergi ke toko elektronik dan membeli adaptor yang memungkinkan kita mengisi daya Perangkat Amerika dengan BritishChargers. Dari sudut pandang pemrograman, kamilah yang akan menjadi produsen adaptor tersebut.

Kita akan membuat Adaptor untuk salah satu yang cocok dengan pola persis yang kita perlukan untuk membuat yang lain. Kami akan mengimplementasikannya sebagai kelas sebagai berikut. Itu tidak harus berupa kelas dan bisa berupa fungsi yang menyoroti apa yang biasanya dilakukan pola adaptor. Kami akan menggunakan kelas yang cocok dengan sebagian besar penggunaan Android.

class AmericanToBritishChargerAdapter(theAmericanCharger:AmericanCharger){
    fun returnNewCharger(): BritishCharger{
            //convert the American charger to a BritishCharger
            //we would change the American charging functionality
            //to British charging functionality to make sure the
            //adapter doesn't destroy the device. The adapter could 
            //, for example, control the power output by dividing by 2
            //our adapter could encompass this functionality in here
           
           var charingPower:Int = charger.chargingPower / 2
           var newBritishCharger = new BritishCharger()
           newBritishCharger.chargingPower = theAmericanCharger.chargingPower/2
        
        return newBritishCharger
    }
}

Dalam dunia pemrograman, perbedaan soket serupa dengan perbedaan metode yang digunakan untuk mengisi daya. Pengisi daya yang memiliki metode berbeda akan membuat pengisi daya tidak dapat digunakan.

 var myBritishDevice = new BritishDevice()
var americanChargerIFound = new AmericanCharger()

Mencoba memanggil metode charge() di myBritishDevice dengan americanChargerIFound tidak akan berfungsi karena AmericanDevice hanya menerima AmericanCharger

Jadi tidak mungkin melakukan hal ini

 var myBritishDevice = new BritishDevice()
var americanChargerIFound = new AmericanCharger()
myBritishDevice.charge(americanChargerIFound)

Dalam skenario ini adaptor yang kami buat

AmericanToBritishChargerAdapter kini berguna. Kita bisa menggunakan metode returnNewCharger() untuk membuat BritishCharger baru, yang bisa kita gunakan untuk mengisi daya. Yang kita butuhkan hanyalah membuat instance adaptor kita dan mengisinya dengan AmericanCharger yang kita miliki, dan itu akan membuat BritishCharger yang bisa kita gunakan

var myBritishDevice = new BritishDevice()
var americanChargerIFound = new AmericanCharger()
//We create the adapter and feed it the americanCharger
var myAdapter =  AmericanToBritishChargerAdapter(theAmericanCharger)
//calling returnNewCharger from myAdapter would return a BritishCharger
var britishChargerFromAdapter = myAdapter.returnNewCharger()
//and once we have the britishCharger we can now use it
myBritishDevice.charge(britishChargerFromAdapter)

RecyclerView.LayoutManager

Saat berhadapan dengan ViewGroup kita akan menempatkan Views di dalamnya. LayoutManager-lah yang bertugas menjelaskan bagaimana Tampilan ditata di dalamnya.

Sebagai perbandingan, saat bekerja dengan Linearlayout ViewGroup, use case yang kita inginkan adalah kemampuan untuk menempatkan item baik secara vertikal maupun horizontal. Hal ini mudah diterapkan dengan menambahkan atribut orientasi, yang memberi tahu kita bagaimana tata letak linier akan ditempatkan di layar. Kita bisa melakukan ini dengan menggunakan android:orientation=VERTICAL|HORIZONTAL atribut.

Kami juga memiliki ViewGroup lain yang disebut GridLayout, kasus penggunaannya adalah ketika kami ingin menempatkan Tampilan dalam struktur Grid persegi panjang. Hal ini mungkin terjadi karena alasan seperti membuat data yang kami sajikan kepada pengguna aplikasi mudah digunakan. Secara desain, GridLayout memungkinkan konfigurasi untuk membantu Anda mencapai tujuan ini dengan memiliki konfigurasi di mana kita dapat menentukan dimensi grid, misalnya kita dapat memiliki grid 4×4, grid 3 x 2.

RecyclerView.ViewHolder

ViewHolder adalah kelas abstrak yang juga kami kembangkan dari RecyclerView. ViewHolder memberi kita metode umum untuk membantu kita mereferensikan Tampilan yang telah kita tempatkan di RecyclerView bahkan setelah mesin Recycling di RecyclerView mengubah berbagai referensi yang tidak kita ketahui.

Daftar Besar

RecyclerView digunakan ketika kita ingin menyajikan kumpulan Tampilan yang sangat besar kepada pengguna, namun tetap tidak menguras tenaga kita. RAM di perangkat kami untuk setiap instance Tampilan yang dibuat.

Jika kita mengambil contoh Daftar Kontak, kita akan memiliki gambaran umum tentang bagaimana satu kontak akan terlihat dalam daftar. Yang akan kita lakukan adalah membuat tata letak templat – yang sebenarnya adalah Tampilan – dengan slot tempat berbagai data dari daftar kontak kita akan diisi. Berikut ini adalah kode semu yang menjelaskan seluruh tujuan:

//OneContactView
<OneContact>
<TextView>{{PlaceHolderForName}}</TextView>
<TextView>{{PlaceHolderForAddress}}</TextView>
<ImageView>{{PlaceHolderForProfilePicture}}</ImageView>
<TextView>{{PlaceHolderForPhoneNumber}}</TextView>
</OneContact>

Kami kemudian akan memiliki Daftar Kontak seperti ini

 <ContactList>
</ContactList>

Jika ini masalahnya, kami melakukan hardcoding pada konten, kami tidak akan memiliki cara terprogram untuk menambahkan konten baru ke daftar tanpa menulis ulang aplikasi. Untungnya bagi kami. Menambahkan Tampilan ke ViewGroup didukung oleh addView(view:View) Metode.

Meskipun demikian, RecyclerView tidak akan menambahkan tampilan anak-anak ke dalamnya.

Dalam kasus penggunaan kami, kami akan memiliki daftar kontak yang panjang. Untuk setiap kontak dalam daftar, kita perlu membuat OneContactView dan mengisi data di dalam View agar sesuai dengan bidang di kelas Kontak kita. Lalu setelah kita memiliki tampilannya, kita perlu menambahkannya ke RecyclerView untuk menampilkan daftarnya.

data  class Contact(var name:String, var address:String, var pic:String, var phoneNumber:Int)

var contact1 = Contact("Guru","Guru97", "SomePic1.jpg", 991)
var contact2 = Contact("Guru","Guru98", "SomePic2.jpg", 992)
var contact3 = Contact("Guru","Guru99", "SomePic3.jpg", 993)

var myContacts:ArrayList<Contact> = arrayListOf<Contact>(contact1,contact2,contact3)

Kami memiliki serangkaian kontak yang disebut OneContactView. Ini berisi slot untuk mengambil konten dari kelas Kontak dan menampilkannya. Di RecyclerView kita harus menambahkan Tampilan ke dalamnya sehingga dapat membantu kita dalam kemampuan mendaur ulangnya.

RecyclerView tidak benar-benar mengizinkan kita menambahkan tampilan tetapi memungkinkan kita menambahkan ViewHolder. Jadi, dalam skenario ini, kita mempunyai dua bagian yang ingin kita sambungkan namun tidak cocok. Di sinilah Adaptor kita berperan. RecyclerView memberi kita Adaptor yang mirip dengan milik kita AmericanToBritishChargerAdapter() dari sebelumnya yang memungkinkan kami mengubah AmericanCharger kami yang tidak dapat digunakan dengan BritishDevice kami menjadi sesuatu yang dapat digunakan, mirip dengan adaptor daya di kehidupan nyata.

Dalam skenario ini, adaptor akan mengambil rangkaian Kontak dan Tampilan kami, dan dari sana menghasilkan ViewHolders yang bersedia diterima oleh RecyclerView.

RecyclerView menyediakan antarmuka yang dapat kita perluas untuk membuat Adaptor melalui kelas RecyclerView.Adapter. Di dalam Adaptor ini terdapat cara untuk membuat kelas ViewHolder yang ingin digunakan oleh RecyclerView. Jadi yang kita punya situasinya sama seperti sebelumnya, tapi dengan satu tambahan yaitu Adaptor.

Kami memiliki serangkaian Kontak, tampilan untuk menampilkan satu kontak OneContactView. RecyclerView adalah daftar Tampilan yang menyediakan layanan daur ulang tetapi hanya bersedia menggunakan ViewHolders

Namun dalam skenario ini, kita sekarang memiliki kelas RecyclerView.Adapter, yang memiliki metode untuk membuat ViewHolders di dalamnya.

fun createViewHolder(@NonNull parent: ViewGroup, viewType: Int): ViewHolder

RecyclerView.ViewHolder adalah kelas abstrak yang menggunakan View kita sebagai argumen dan mengubahnya menjadi ViewHolder.

Ia menggunakan pola pembungkus yang digunakan untuk memperluas kemampuan kelas.

Dasar #2 – Pola pembungkus

Kita akan menggunakan contoh sederhana untuk mendemonstrasikan bagaimana kita dapat membuat Hewan berbicara.

sealed trait Animal{
    fun sound():String
}

data class Cat(name:String):Animal{
    fun sound(){
        "Meow"
        }
}
data class Dog(name:String):Animal{
    fun sound(){
        "Woof"
        }
}

var cat1 = Cat("Tubby")
var dog1 = Dog("Scooby")
cat1.sound() //meow
dog1.sound() //woof

Dalam contoh di atas, kita memiliki dua hewan. Jika kebetulan, kami ingin menambahkan metode agar dapat berbicara, namun pembuat perpustakaan tidak menyenangkan, kami masih dapat menemukan cara. Apa yang kita perlukan adalah pembungkus untuk kelas Hewan kita. Kita akan melakukan ini dengan menggunakan Hewan sebagai konstruktor untuk kelas kita

 class SpeechPoweredAnimalByWrapper(var myAnimal:Animal){

    fun sound(){
        myAnimal.sound()
    }

    speak(){
        println("Hello, my name is ${myAnimal.name}")
    }
}

Sekarang kita dapat meneruskan contoh hewan ke SpeechPoweredAnimalByWrapper. Memanggil metode sound() di dalamnya akan memanggil metode sound() hewan yang diteruskan. Kita juga mempunyai metode speak() tambahan, yang dianggap sebagai fungsi baru yang kita tambahkan ke hewan yang diteruskan. Kita dapat menggunakannya sebagai berikut:

var cat1 =  Cat("Garfield")
cat1.sound()//"meow"
cat1.speak()// doesn't work as it isn't implemented
var talkingCat = new SpeechPoweredAnimalByWrapper(cat1)
talkingCat.sound() //"meow" the sound method calls the one defined for cat1
talkingCat.speak() //"Hello, my name is Garfield"

Dengan menggunakan pola ini, kita dapat mengambil kelas dan menambahkan fungsionalitas. Yang kita perlukan hanyalah meneruskan instance kelas dan metode baru yang ditentukan oleh kelas pembungkus kita.

Dalam kasus kami di atas, kami menggunakan kelas konkret. Hal yang sama juga dapat diterapkan di kelas Abstrak. Yang perlu kita lakukan hanyalah menambahkan perubahan kelas SpeechPoweredAnimalByWrapper menjadi abstrak dan selesai. Kami akan mengubah nama kelas menjadi lebih pendek agar lebih mudah dibaca.

abstract class SpeechPowered(var myAnimal:Animal){

    fun sound(){
        myAnimal.sound()
    }

    speak(){
        println("Hello, my name is ${myAnimal.name}")
    }
}

Itu sama seperti sebelumnya, tetapi artinya berbeda. Di kelas normal, kita bisa memiliki instance kelas dengan cara yang sama seperti kita membuat cat1 dan dog1. Kelas abstrak, bagaimanapun, tidak dimaksudkan untuk dipakai tetapi dimaksudkan untuk memperluas kelas lain. Jadi bagaimana kita menggunakan kelas abstrak SpeechPowered(var myAnimal:Animal) yang baru. Kita dapat menggunakannya dengan membuat kelas-kelas baru yang akan memperluasnya dan pada gilirannya, memperoleh fungsionalitasnya.

Dalam contoh kita, kita akan membuat kelas SpeechPoweredAnimal yang memperluas kelas tersebut

class SpeechPoweredAnimal(var myAnimal:Animal):SpeechPowered(myAnimal)
var cat1 =  Cat("Tubby")
var speakingKitty = SpeechPoweredAnimal(cat1)
speakingKitty.speak() //"Hello, my name is Tubby"

Ini adalah pola yang sama yang digunakan di ViewHolder. Kelas RecyclerView.ViewHolder adalah kelas abstrak yang menambahkan fungsionalitas pada Tampilan, sama seperti kita menambahkan metode bicara pada hewan. Fungsionalitas tambahan inilah yang membuatnya berfungsi ketika berhadapan dengan RecyclerView.

Beginilah cara kami membuat OneContactViewHolder dari OneContactView

//The View argument we pass is converted to a ViewHolder which uses the View to give it more abilities and in turn work with the RecyclerView
class OneContactViewHolder(ourContactView: View) : RecyclerView.ViewHolder(ourContactView)

RecyclerView memiliki Adaptor yang memungkinkan kita menghubungkan array Kontak ke ContactsView dengan RecyclerView

Menambahkan Tampilan

ViewGroup tidak menggambar ulang ViewGroup secara otomatis, tetapi mengikuti jadwal tertentu. Mungkin saja pada perangkat Anda, ViewGroup digambar ulang setiap 10 ms atau 100 ms, atau jika kita memilih angka yang tidak masuk akal, misalnya 1 menit, saat kita menambahkan View ke ViewGroup, Anda akan melihat perubahan 1 menit kemudian saat ViewGroup "di-refresh".

RecyclerView.Pendaur Ulang

Dasar #3. cache

Salah satu contoh terbaik dimana kita rutin melakukan refresh adalah pada Browser. Bayangkan, misalnya situs yang kita kunjungi bersifat statis dan tidak mengirimkan konten secara dinamis, kita perlu terus melakukan refresh untuk melihat perubahannya.

Untuk contoh ini, bayangkan situs yang dimaksud adalah twitter. Kami akan memiliki serangkaian tweet statis yang terdaftar dan satu-satunya cara kami dapat melihat Tweet baru adalah dengan mengklik tombol segarkan untuk mengambil kembali kontennya.

Mengecat ulang seluruh layar jelas merupakan hal yang mahal. Jika kita membayangkan jika hal ini terjadi, kita mempunyai bandwidth yang terbatas pada penyedia telepon kita. Dan daftar tweet kami memiliki banyak gambar dan video, akan memakan biaya besar untuk mengunduh ulang semua konten halaman di setiap penyegaran.

Kami memerlukan cara untuk menyimpan Tweet yang sudah dimuat dan memastikan permintaan kami berikutnya memiliki kemampuan untuk mengucapkan Tweet yang sudah dimilikinya. Oleh karena itu, ia tidak mengunduh ulang semuanya dan hanya mendapatkan Tweet baru yang dimilikinya dan juga memeriksa apakah beberapa Tweet yang telah disimpan secara lokal sudah tidak ada lagi sehingga dapat menghapusnya secara lokal. Apa yang kami jelaskan disebut Caching.

Informasi yang kita kirimkan ke website tentang konten yang kita miliki disebut metadata. Jadi sebenarnya kami tidak hanya mengatakan “kami ingin memuat situs Anda”, kami mengatakan “kami ingin memuat situs Anda, dan inilah beberapa konten yang telah kami simpan sejak terakhir kali kami memuatnya, silakan gunakan untuk hanya kirimkan kepada kami apa yang tidak ada di sana, jadi kami tidak menggunakan banyak bandwidth karena kami tidak memiliki banyak sumber daya.”

Panggilan Tata Letak – Daftar Tweet pasti gila

Contoh panggilan tata letak adalah scrollToPosition

Ini adalah contoh umum yang terjadi pada aplikasi chatting. Jika seseorang di rangkaian obrolan membalas gelembung obrolan dari sebelumnya, beberapa aplikasi obrolan menyertakan balasan dan tautan ke gelembung obrolan, yang setelah diklik akan mengarahkan Anda ke tempat pesan asli Anda berada.

Dalam kasus ini, kita memanggil metode ini sebelum LayoutManager ditambahkan ke RecyclerView dan sebelum kita memiliki RecyclerView.Adapter, scrollToPosition(n:Int) diabaikan begitu saja.

Komunikasi antar Komponen RecyclerView

Dasar #4. Panggilan balik

RecyclerView dalam melakukan tugasnya memiliki banyak bagian yang bergerak. Itu harus berurusan dengan LayoutManager yang memberitahu kita bagaimana mengatur Tampilan, baik secara Linear atau dalam Grid. Itu harus berurusan dengan Adaptor yang melakukan tugas mengubah item contactList kami menjadi Tampilan OneContactView dan kemudian menjadi ViewHolders OneContactViewHolder sehingga RecyclerView bersedia bekerja dalam metode yang disediakannya untuk kami.

Bahan mentah untuk RecyclerView adalah Tampilan kami, misalnya OneContactView dan sumber data.

contactList:Array<Contact>

Kami telah menggunakan skenario sederhana sebagai titik awal untuk merasakan apa yang ingin dicapai oleh RecyclerView.

Kasus dasar ketika kita memiliki array statis 1000 kontak yang ingin kita tunjukkan kepada pengguna mudah dimengerti.

Mesin RecyclerView benar-benar mulai berfungsi ketika daftarnya tidak lagi statis.

Dengan daftar dinamis, kita harus memikirkan apa yang terjadi pada Tampilan di layar saat kita menambahkan item ke daftar atau menghapus item dari daftar.

RecyclerView.LayoutManager

Selain memutuskan bagaimana pandangan kita akan ditata secara Linear atau Grid. LayoutManager melakukan banyak pekerjaan dalam membantu Pendaur Ulang mengetahui kapan harus melakukan Daur Ulang.

Ini bertanggung jawab untuk melacak Tampilan yang saat ini terlihat di Layar dan mengkomunikasikan informasi ini ke mekanisme Daur Ulang. Saat pengguna menggulir ke bawah, Manajer tata letak bertanggung jawab untuk memberi tahu sistem Daur Ulang tentang Tampilan yang tidak fokus di bagian atas sehingga dapat digunakan kembali alih-alih tetap di sana dan menghabiskan memori atau alih-alih menghancurkannya dan harus membuat yang baru.

Artinya, LayoutManager perlu melacak keberadaan pengguna saat mereka menggulir daftar kita. Hal ini dilakukan dengan memiliki daftar posisi yang merupakan basis indeks, yaitu item pertama dimulai dari 0 dan meningkat agar sesuai dengan jumlah item dalam daftar kita.

Jika kita dapat melihat 10 item dalam daftar, katakanlah 100, pada awalnya, LayoutManager menyadari bahwa ia memiliki fokus tampilan-0 hingga Tampilan-9. Saat kita menggulir, LayoutManager dapat menghitung tampilan yang keluar fokus.

LayoutManager dapat melepaskan tampilan ini ke mekanisme Daur Ulang sehingga dapat digunakan kembali (data baru dapat diikat ke dalamnya, misalnya data kontak Tampilan dapat dihapus dan data Kontak baru dari segmen berikutnya dapat menggantikan placeholder).

Ini akan menjadi kasus yang menyenangkan jika Daftar yang kita miliki bersifat statis, namun salah satu kasus penggunaan paling umum dalam penggunaan RecyclerView adalah dengan daftar dinamis di mana data dapat berasal dari titik akhir online atau bahkan mungkin dari Sensor. Tidak hanya data yang ditambahkan, namun data pada Daftar kami terkadang dihapus atau diperbarui.

Keadaan data yang dinamis dapat mempersulit pertimbangan tentang LayoutManager. Karena alasan ini, LayoutManager menyimpan daftarnya sendiri tentang item dan posisi, yang terpisah dari Daftar yang digunakan komponen Daur Ulang. Ini memastikan ia melakukan pekerjaan tata letaknya dengan benar.

Pada saat yang sama, LayoutManager RecyclerView tidak ingin salah menggambarkan data yang dimilikinya. Agar dapat beroperasi dengan benar, LayoutManager melakukan sinkronisasi dengan RecyclerView.Adapter pada interval tertentu (60 ms) yang membagikan informasi tentang item Daftar kami. yaitu, Item yang ditambahkan, diperbarui, dihapus, dipindahkan dari satu posisi ke posisi lain). LayoutManager, setelah menerima informasi ini, mengatur ulang konten pada Layar agar sesuai dengan perubahan saat diperlukan.

Banyak operasi inti yang berhubungan dengan RecylerView berkisar pada komunikasi antara RecyclerView.LayoutManager dan RecyclerView.Adapter yang menyimpan daftar data kami yang terkadang statis atau terkadang dinamis.

Lebih dari itu, RecyclerView memberi kita metode yang bisa kita gunakan untuk mendengarkan kejadian seperti onBindViewHolder ketika RecyclerView.Adapter kita mengikat konten dari Daftar kita, misalnya Kontak ke ViewHolder sehingga sekarang terbiasa menampilkan info di Layar.

Lainnya adalah onCreateViewHolder, yang memberi tahu kita kapan RecyclerView. Adaptor mengambil Tampilan biasa seperti OneContactView dan mengubahnya menjadi item ViewHolder yang dapat digunakan oleh RecyclerView. Dari ViewHolder kami untuk digunakan oleh RecyclerView. onViewTerpisah

Terlepas dari mekanisme inti yang memungkinkan Daur Ulang. RecyclerView menyediakan cara untuk menyesuaikan perilaku tanpa memengaruhi Daur Ulang.

Penggunaan kembali Tampilan menyulitkan kita melakukan hal-hal umum yang biasa kita lakukan dengan tampilan statis seperti bereaksi terhadap peristiwa onClick.

Seperti yang kita ketahui bahwa RecyclerView.LayoutManager yang menyajikan Tampilan kepada pengguna mungkin sejenak memiliki daftar item yang berbeda dari RecyclerView.Adapter yang memiliki daftar yang telah kita simpan dalam database atau streaming dari sumber. Menempatkan peristiwa OnClick secara langsung di Tampilan dapat menyebabkan perilaku yang tidak diharapkan, seperti menghapus kontak yang salah atau mengubahnya.

Gradle

Jika kita ingin menggunakan RecyclerView, kita perlu menambahkannya sebagai dependensi di file build .gradle kita.

Dalam contoh berikut ini kami telah menggunakan implementasi “androidx.recyclerview:recyclerview:1.1.0” yang merupakan versi terkini menurut artikel ini.

Setelah menambahkan ketergantungan ke kami Gradle file, kita akan diminta oleh Android Studio ke Synccatat perubahannya,

Ini adalah bagaimana kami Gradle file akan terlihat seperti setelah menambahkan RecyclerView dalam proyek kosong hanya dengan default.

apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.2"
    defaultConfig {
        applicationId "com.guru99.learnrecycler"
        minSdkVersion 17
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
             'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.core:core-ktx:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

    implementation "androidx.recyclerview:recyclerview:1.1.0"
}

Kami hanya memiliki satu file tata letak saat ini. Kita akan mulai dengan contoh sederhana di mana kita akan menggunakan RecyclerView untuk menampilkan daftar nama buah di layar.

Daftar barang

Kita akan menavigasi ke file MainActivity dan membuat array dengan nama buah di dalamnya tepat sebelum metode onCreate() yang dihasilkan selama penyiapan.

package com.guru99.learnrecycler

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

class MainActivity : AppCompatActivity() {

    var fruitNames:Array<String> = arrayOf<String>("Banana", "Mango", "Passion fruit", "Orange", "Grape")

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}

Tujuan kami selanjutnya adalah menampilkan daftar ini di layar menggunakan RecyclerView.

Untuk melakukan ini, kita akan menavigasi ke direktori tata letak yang menampung Tata Letak kita dan membuat Tampilan yang akan bertanggung jawab untuk menampilkan satu buah.

Tata letak yang akan digunakan untuk setiap item dalam daftar kami

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/fruitName"
    />
</TextView>

Pada TextView di atas, kami telah menambahkan kolom id yang akan digunakan untuk mengidentifikasi Tampilan.

Ini tidak dihasilkan secara default. Kami memiliki TextView id nama buah kami untuk mencocokkan data, yang akan terikat padanya.

Menambahkan RecyclerView ke tata letak utama

Dalam aktivitas yang sama, ada file tata letak main_layout.xml yang dibuat untuk kita secara default.

Jika kita memilih proyek kosong. Ini akan menghasilkan XML berisi ConstraintLayout dan di dalamnya akan ada TextView dengan teks "Halo".

Kami akan menghapus semua konten dan membuat tata letaknya hanya berisi RecyclerView seperti di bawah ini:

<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView 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:id="@+id/fruitRecyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" />

Kami juga menambahkan atribut id untuk RecyclerView yang akan kami gunakan sebagai referensi dalam kode kami.

 android:id="@+id/fruitRecyclerView"

Kami kemudian akan menavigasi kembali ke file MainActivity kami. Dengan menggunakan id yang telah kita buat, kita akan dapat mereferensikan Tampilan yang baru saja kita buat.

Kita akan mulai dengan mereferensikan RecyclerView menggunakan metode findViewById() yang disediakan oleh Android. Kami akan melakukan ini dalam metode onCreate() kami.

Metode onCreate() kita akan terlihat seperti berikut.

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        var myFruitRecyclerView: RecyclerView = findViewById(R.id.fruitRecyclerView)
    }

Buat ViewHolder

Selanjutnya, kita akan membuat RecyclerView.ViewHolder yang bertanggung jawab untuk mengambil View kita dan mengubahnya menjadi ViewHolder, yang digunakan RecyclerView untuk menampilkan item kita.

Kita akan melakukan ini tepat setelah metode onCreate() yang menyenangkan.

package com.guru99.learnrecycler

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import androidx.recyclerview.widget.RecyclerView

class MainActivity : AppCompatActivity() {

    var fruitNames:Array<String> = arrayOf<String>("Banana", "Mango", "Passion fruit", "Orange", "Grape")

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        var myFruitRecyclerView: RecyclerView = findViewById(R.id.fruitRecyclerView)
    }
    
    class FruitViewHolder(fruitView: View): RecyclerView.ViewHolder(fruitView)
    
}

Buat RecyclerViewAdapter

Selanjutnya, kita akan membuat kelas FruitArrayAdapter yang memperluas kelas RecyclerView.Adapter.

FruitArrayAdapter yang kita buat akan bertanggung jawab untuk melakukan hal berikut.

Ini akan mengambil nama buah dari susunan buah. Ini akan membuat ViewHolder menggunakan tampilan one_fruit_view.xml. Kemudian akan mengikat buah ke ViewHolder, dan secara dinamis mengikat konten ke Tampilan yang kami buat one_fruit_view.xml.

package com.guru99.learnrecycler

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import androidx.recyclerview.widget.RecyclerView

class MainActivity : AppCompatActivity() {

    var fruitNames:Array<String> = arrayOf<String>("Banana", "Mango", "Passion fruit", "Orange", "Grape")

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        var myFruitRecyclerView: RecyclerView = findViewById(R.id.fruitRecyclerView)
    }
    
    class FruitViewHolder(fruitView: View): RecyclerView.ViewHolder(fruitView)
    
    class FruitArrayAdapter(var fruitArray: Array<String>) : RecyclerView.Adapter<FruitViewHolder>()
}

Android Studio akan menambahkan coretan merah pada FruitArrayAdapter, memberi tahu kita bahwa kita perlu mengimplementasikan metode yang dapat digunakan RecyclerView untuk menghubungkan array kita ke ViewHolder yang dapat digunakan oleh RecyclerView.

   class FruitListAdapter(var fruitArray: Array<String>) : RecyclerView.Adapter<FruitViewHolder>() {
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FruitViewHolder {
            
        }

        override fun getItemCount(): Int {
         
        }

        override fun onBindViewHolder(holder: FruitViewHolder, position: Int) {
          
        }
    }

Kita akan mulai dengan bagian termudah dari kode yang dihasilkan adalah metode getItemCount(). Kita tahu cara mendapatkan jumlah item dalam array kita dengan memanggil metode array.length.

class FruitListAdapter(var fruitArray: Array<String>) : RecyclerView.Adapter<FruitViewHolder>() {
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FruitViewHolder {
            
        }

        override fun getItemCount(): Int {
         return fruitArray.size
        }

        override fun onBindViewHolder(holder: FruitViewHolder, position: Int) {
          
        }
    }

Kemudian kita akan menerapkan metode override fun onCreateViewHolder.

Di sinilah RecyclerView meminta kita membantunya membuat FruitHolder untuknya.

Jika kita ingat, seperti inilah tampilan kelas FruitViewHolder kita:

class FruitViewHolder(fruitView: View): RecyclerView.ViewHolder(fruitView)

Ini membutuhkan FruitView yang kami buat sebagai file xml one_fruit_view.xml

Kita dapat membuat referensi ke xml ini dan mengubahnya menjadi Tampilan sebagai berikut.

class FruitListAdapter(var fruitArray: Array<String>) : RecyclerView.Adapter<FruitViewHolder>() {

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FruitViewHolder {

            var fruitView = LayoutInflater.from(parent.context).inflate(R.layout.one_fruit_view, parent, false)

            var fruitViewHolder = FruitViewHolder(fruitView)

            return fruitViewHolder

        }

        override fun getItemCount(): Int {
            return fruitArray.size
        }

        override fun onBindViewHolder(holder: FruitViewHolder, position: Int) {

        }
    }

Bit yang tersisa adalah override

fun onBindViewHolder(holder: FruitViewHolder, position: Int)

RecyclerView.Adapter bertanya dengan bilangan bulat posisi, yang akan kita gunakan untuk mengambil item dari daftar kita. Ini juga memberi kita sebuah pemegang sehingga kita dapat mengikat item yang kita dapatkan dari FruitArray ke Tampilan yang disimpan di dalam pemegang tampilan.

Tampilan yang disimpan di dalam ViewHoder dapat diakses melalui bidang ViewHolder.itemView. Setelah kita mendapatkan tampilannya, kita dapat menggunakan id FruitName yang kita buat sebelumnya untuk mengatur konten.

  override fun onBindViewHolder(holder: FruitViewHolder, position: Int) {

            var ourFruitTextView = holder.itemView.findViewById<TextView>(R.id.fruitName)

            var aFruitName = fruitArray.get(position)

            ourFruitTextView.setText(aFruitName)
        }

Dengan itu FruitArrayAdapter kita sudah lengkap dan tampilannya seperti berikut.

class FruitListAdapter(var fruitArray: Array<String>) : RecyclerView.Adapter<FruitViewHolder>() {

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FruitViewHolder {

            var fruitView = LayoutInflater.from(parent.context).inflate(R.layout.one_fruit_view, parent, false)

            var fruitViewHolder = FruitViewHolder(fruitView)

            return fruitViewHolder
        }

        override fun getItemCount(): Int {
            return fruitArray.size
        }

        override fun onBindViewHolder(holder: FruitViewHolder, position: Int) {

            var ourFruitTextView = holder.itemView.findViewById<TextView>(R.id.fruitName)

            var aFruitName = fruitArray.get(position)

            ourFruitTextView.setText(aFruitName)
        }
    }

Terakhir, kami siap menyambungkan sisa bagian RecyclerView kami. Yang membuat LayoutManager, yang akan memberitahu RecyclerView cara menampilkan konten daftar. Apakah akan ditampilkan secara linear menggunakan LinearLayoutManager atau dalam grid menggunakan GridLayoutManager atau StaggeredGridLayoutManager.

Buat Manajer Tata Letak

Kita akan kembali ke dalam fungsi onCreate dan menambahkan LayoutManager

 override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        var myFruitRecyclerView: RecyclerView = findViewById(R.id.fruitRecyclerView)
        
        var fruitLinearLayout = LinearLayoutManager(this)
        
        myFruitRecyclerView.layoutManager =fruitLinearLayout
        
    }

Kaitkan adaptor kita ke item dan atur di RecyclerView

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        var myFruitRecyclerView: RecyclerView = findViewById(R.id.fruitRecyclerView)
        
        var fruitLinearLayout = LinearLayoutManager(this)
        
        myFruitRecyclerView.layoutManager =fruitLinearLayout
        
        var fruitListAdapter = FruitListAdapter(fruitNames)
        
        myFruitRecyclerView.adapter =fruitListAdapter
    }

Kita juga telah membuat instance buahListAdapter dan memberinya array nama buah.

Dan pada dasarnya, kita semua sudah selesai.

Tampilan file MainActivity.kt selengkapnya seperti berikut.

package com.guru99.learnrecycler

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView

class MainActivity : AppCompatActivity() {

    var fruitNames:Array<String> = arrayOf<String>("Banana", "Mango", "Passion fruit", "Orange", "Grape")

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        var myFruitRecyclerView: RecyclerView = findViewById(R.id.fruitRecyclerView)

        var fruitLinearLayout = LinearLayoutManager(this)

        myFruitRecyclerView.layoutManager =fruitLinearLayout

        var fruitListAdapter = FruitListAdapter(fruitNames)

        myFruitRecyclerView.adapter =fruitListAdapter
    }

    class FruitViewHolder(fruitView: View): RecyclerView.ViewHolder(fruitView)

    class FruitListAdapter(var fruitArray: Array<String>) : RecyclerView.Adapter<FruitViewHolder>() {

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FruitViewHolder {

            var fruitView = LayoutInflater.from(parent.context).inflate(R.layout.one_fruit_view, parent, false)

            var fruitViewHolder = FruitViewHolder(fruitView)

            return fruitViewHolder
        }

        override fun getItemCount(): Int {
            return fruitArray.size
        }

        override fun onBindViewHolder(holder: FruitViewHolder, position: Int) {

            var ourFruitTextView = holder.itemView.findViewById<TextView>(R.id.fruitName)

            var aFruitName = fruitArray.get(position)

            ourFruitTextView.setText(aFruitName)
        }
    }
}

Unduh Proyek