Pagination pada Android dengan Kotlin

Pada saat kita membuat aplikasi kadang kita berhubungan dengan sebuah data, dan pastinya jika berkaitan dengan sebuah data pasti erat kaitannya dengan Rest Api. Pada sebuah kasus aplikasi yang sudah sangat besar atau sudah masuk ke ranah Super App seperti aplikasi ojek online(Gojek) yang memiliki pengguna(User) dengan jumlah jutaan pengguna, dengan jumlah data yang digunakan itu sangatlah besar, apabila kita me-request semua data dalam satu waktu maka akan memakan cost yang sangat besar, dan belum tentu semua data yang ada akan digunakan seluruhnya.

Oleh karena itu Pagination diterapkan. Pagination adalh sebuah fitur yang digunakan untuk membatasi tampilan data agar tidak terlalu panjang dan lebih rapi.

Gambar diatas adalah sebuah response dari REST API dummy https://reqres.in dan jika diperhatikan ada properti “page” dan properti lain yang berhubungan dengan page. Jadi jika dideskripsikan, ada 12 data dibagi menjadi 2 page. Untuk mendapatkan response ke page selanjutnya, kita perlu menambahkan parameter lagi.

Bagaimana cara menampilkan setiap page tersebut menjadi satu halaman dengan tetap menerapkan pagination? Nah kita akan menerapkan Endless Recycler View. Yaitu recycler view yang akan memuat data terus menerus jika user scroll down disertai dengan progress bar saat proses request, kurang lebih akan seperti gambar di bawah ini.

Aplikasi yang menerapkan endless recycler view

Pada story ini saya akan memberikan pengalaman saya membuat endless recycler view dari REST API reqres.in tadi.

Pertama temen-temen buat project Android Studio masing-masing. kemudian kita akan menambahkan beberapa dependency yang diperlukan di build.gradle

implementation ‘com.squareup.retrofit2:retrofit:2.6.2’
implementation ‘com.squareup.retrofit2:convertergson:2.6.2’
implementation ‘androidx.recyclerview:recyclerview:1.1.0’
implementation “androidx.swiperefreshlayout:swiperefreshlayout:1.0.0

Kemudian klik sync now pada pojok kanan atas project

Setelah proses synchronize selesai, kita akan buat interface untuk mengatur fungsi-fungsi REST API. Kita akan buat kotlin file class bernama Api.kt dan isikan dengan kode berikut:

interface Api {
@GET(“users”)
fun getUsers(
@QueryMap parameters: HashMap<String, String>
): Call<UsersResponse>
}

Kemduian buat kotlin file class bernama RetrofitClient.kt dan di dalamnya isikan dengan kode berikut:

object RetrofitClient {
private const val BASE_URL = “https://reqres.in/api/" val instance: Api by lazy {
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build() retrofit.create(Api::class.java)
}
}

Di interface Api kita memiliki fungsi getUsers dengan nilai balik Call bertipe UsersResponse. Kita perlu membuat data class atau model yang merupakan representasi response dari REST API. Buatlah kotline file class bernama UsersResponse.kt kemudian isikan dengan kode berikut:

data class UsersResponse(
val data: ArrayList<Data>,
val page: Int,
@SerializedName(“total_pages”)
val totalPages: Int
)

dan buatlah kotlin file class bernama Data.kt dan isikan dengan kode berikut:

data class Data(
val email: String,
@SerializedName(“first_name”)
val firstName: String,
@SerializedName(“last_name”)
val lastName: String
)

Karena disini kita akan menampilkan sebuah recycler view maka kita memerlukan Adapter dan Layout dari item nya. Kita buat terlebih dahulu layout resource file kemudian beri nama item_layout.xml dan isikan dengan kode berikut:

<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android"
xmlns:tools=”http://schemas.android.com/tools"
android:layout_width=”match_parent”
android:layout_height=”160dp”
android:orientation=”vertical”
android:padding=”16dp”> <TextView
android:id=”@+id/tvEmail”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
tools:text=”ngodinglife@gmail” /> <TextView
android:id=”@+id/tvName”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
tools:text=”Nama saya”/></LinearLayout>

Kemudian buat lagi kotlin file class bernama UsersAdapter.kt dan isikan kode berikut:

class UsersAdapter : RecyclerView.Adapter<UsersAdapter.UsersViewHolder>(){   private var list = ArrayList<Data>()   inner class UsersViewHolder(itemView: View): RecyclerView.ViewHolder(itemView){
fun bind(data: Data){
with(itemView){
tvEmail.text = data.email
val name = data.firstName + data.lastName
tvName.text = name
}
}
} override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UsersViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_user, parent, false)
return UsersViewHolder(view)
} override fun getItemCount(): Int = list.size override fun onBindViewHolder(holder: UsersViewHolder, position: Int) {
holder.bind(list[position])
} fun addList(items: ArrayList<Data>){
list.addAll(items)
notifyDataSetChanged()
} fun clear(){
list.clear()
notifyDataSetChanged()
}
}

kemudian edit layout activity_main.xml menjadi kode berikut:

<androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android=”http://schemas.android.com/apk/res/android"
xmlns:tools=”http://schemas.android.com/tools"
android:id=”@+id/swipeRefresh”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
tools:context=”.MainActivity”> <ScrollView
android:layout_width=”match_parent”
android:layout_height=”match_parent”> <LinearLayout
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:orientation=”vertical”> <androidx.recyclerview.widget.RecyclerView
android:id=”@+id/rvUsers”
android:layout_width=”match_parent”
android:layout_height=”wrap_content” /> <ProgressBar
android:id=”@+id/progressBar”
android:layout_width=”match_parent”
android:layout_height=”48dp” /> </LinearLayout> </ScrollView></androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

kemudian edit juga MainActivity.kt menjadi:

class MainActivity : AppCompatActivity(), SwipeRefreshLayout.OnRefreshListener {private lateinit var adapter: UsersAdapter
private lateinit var layoutManager: LinearLayoutManager
private var page = 1
private var totalPage: Int = 1private var isLoading = falseoverride fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)layoutManager = LinearLayoutManager(this)
swipeRefresh.setOnRefreshListener(this)
setupRecyclerView()
getUsers(false)rvUsers.addOnScrollListener(object : RecyclerView.OnScrollListener(){
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {Log.d("MainActivity", "onScrollChange: ")
val visibleItemCount = layoutManager.childCount
val pastVisibleItem = layoutManager.findFirstVisibleItemPosition()
val total = adapter.itemCount
if (!isLoading && page < totalPage){
if (visibleItemCount + pastVisibleItem>= total){
page++
getUsers(false)
}
}
super.onScrolled(recyclerView, dx, dy)
}
})
}private fun getUsers(isOnRefresh: Boolean) {
isLoading = true
val translateAnimation = TranslateAnimation(0F,50F,0F,0F)
translateAnimation.duration = 200
translateAnimation.isFillEnabled = true
translateAnimation.fillAfter = true
progressBar.startAnimation(translateAnimation)
if (!isOnRefresh) progressBar.visibility = View.VISIBLE
Handler().postDelayed({
val parameters = HashMap<String, String>()
parameters["page"] = page.toString()
Log.d("PAGE", "$page")
RetrofitClient.instance.getUsers(parameters).enqueue(object : Callback<UsersResponse>{
override fun onFailure(call: Call<UsersResponse>, t: Throwable) {
Toast.makeText(this@MainActivity, "${t.message}", Toast.LENGTH_SHORT).show()
progressBar.visibility = View.GONE
isLoading = false
swipeRefresh.isRefreshing = false
}override fun onResponse(call: Call<UsersResponse>, response: Response<UsersResponse>) {
totalPage = response.body()?.total_pages!!
Log.d("PAGE", "totalPage: $totalPage")
val listResponse = response.body()?.data
if (listResponse != null){
Log.d("PAGE", "listResponse != null")
adapter.addList(listResponse)
}
if (page == totalPage){
progressBar.visibility = View.GONE
}else{
progressBar.visibility = View.INVISIBLE
}
isLoading = false
swipeRefresh.isRefreshing = false
}
})
}, 4000)}private fun setupRecyclerView() {
rvUsers.setHasFixedSize(true)
rvUsers.layoutManager = layoutManager
adapter = UsersAdapter()
rvUsers.adapter = adapter
}override fun onRefresh() {
adapter.clear()
page = 1
getUsers(true)
}
}

dan sebelum dijalankan kita perlu menambahkan uses permission internet pada android manifest

<uses-permission android:name=”android.permission.INTERNET”/>

Kemudian jalankan

Aplikasi yang menerapkan endless recycler view

Maka kurang lebih tampilan nya akan seperti gambar diatas.

Leave a Comment