DEV Community

Yogesh Choudhary Paliyal
Yogesh Choudhary Paliyal

Posted on • Originally published at yogeshpaliyal.com on

Universal Recycler Adapter for 90% of your needs

Android Universal Recycler Adapter

Tired of creating 100s of Adapters and View Models.
This Library will make it easy, No need to create an Adapter, ViewHolder for every list

πŸ€” How?

Using Resource Pattern to find the status of the list and show view types according to that.

Step #1. Add the JitPack repository to your build file:

allprojects {
    repositories {
    ...
        maven { url "https://jitpack.io" }
    }
}
Enter fullscreen mode Exit fullscreen mode

Step #2. Add the dependency (See latest release).

Jitpack

dependencies {
    implementation 'com.github.yogeshpaliyal:Android-Universal-Recycler-View-Adapter:+'
}
Enter fullscreen mode Exit fullscreen mode

πŸ› οΈ Used in this Project

🀩 Features

  • Content Listing (Supports Multiple View Types)
  • Loading + Listing (Showing shimmer items for Loading then showing the actual Listing)
  • Loading + LoadMore (Showing loading items and add an item at bottom to create infinite Listing)
  • No Data Found
  • Error Page
  • Async DiffUtils for better performance

When to show which item?

Status List Size Result Behaviour
LOADING 0 Show Loading Cells (default 5 items)
SUCCESS 0 No Record Found Layout will be displayed
ERROR 0 Error Layout Shown
LOADING more than 0 Data Cells + load more at end
SUCCESS more than 0 Data Cells
ERROR more than 0 Data Cells + error cell at the end

XML Variables

To bind your view item with Adapter using dataBinding you have to create use these Variables
name must be as follows

binding

Type should be the same as your resource binding file.
This can be used to update your views in the callback, after changing the variable value in the model, for example, check UserListingActivity.

All Adapters layout using this variable

<variable
            name="binding"
            type="androidx.databinding.ViewDataBinding" />
Enter fullscreen mode Exit fullscreen mode

model

Type should be same as model you are passing to Adapter.

Content layout using this variable

<variable
            name="model"
            type="com.techpaliyal.androidkotlinmvvm.model.BasicModel" />
Enter fullscreen mode Exit fullscreen mode

listener

Type Any/Object, should be same as you passing while create Adapter.

Content & Error layout using this variable

<variable
            name="listener"
            type="com.techpaliyal.androidkotlinmvvm.model.BasicListener" />
Enter fullscreen mode Exit fullscreen mode

message

Type will be String.

Error layout using this variable

<variable
            name="message"
            type="String" />
Enter fullscreen mode Exit fullscreen mode

Show me the code

 private val mAdapter by lazy {
        UniversalRecyclerAdapter.Builder<UserModel>(
            lifecycleOwner = this,
            content = UniversalAdapterViewType.Content(resource = R.layout.item_user,
                object : BasicListener<UserModel> {
                    override fun onClick(model: UserModel) {
                        Toast.makeText(this@LoadingListingActivity, model.name, Toast.LENGTH_SHORT)
                            .show()
                    }
                }),
            loading = UniversalAdapterViewType.Loading(
                resourceLoading = R.layout.layout_loading_full_page,
                defaultLoadingItems = 1
            ),
            error = UniversalAdapterViewType.Error(errorLayout = R.layout.item_error),
            loadingFooter = UniversalAdapterViewType.LoadingFooter(loaderFooter = R.layout.item_loading_more)
        ).build()
    }
Enter fullscreen mode Exit fullscreen mode

Note: All the parameters in **UniversalRecyclerAdapter.Builder* are optional, use only those you want to use*

lifecycleOwner = This will be used to notify your view to update on data change.

content = Your primary list element.

- resource = Element layout id.

- listener = Pass the interface you want to send to your item layout

loading = Your loading list element. (like shimmer or just a loader).

- resourceLoading = loading layout id.

- defaultLoadingItems = Items you want to show while loading.

error = Layout to be shown when Status == Status.ERROR

- errorLayout = error layout id.

- listener = Pass the interface you want to send to your error layout.

Examples

Simple List

List item (File)

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
        <variable
            name="model"
            type="com.techpaliyal.androidkotlinmvvm.model.BasicModel" />
        <variable
            name="listener"
            type="com.techpaliyal.androidkotlinmvvm.listeners.BasicListener" />
    </data>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:padding="5dp"
        android:textSize="16sp"
        android:text="@{model.name}"
        android:onClick="@{()->listener.onClick(model)}"/>

</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Enter fullscreen mode Exit fullscreen mode

Initialize Adapter (File)

 private val mAdapter by lazy {
        UniversalRecyclerAdapter.Builder<BasicModel>(
            lifecycleOwner = this,
            content = UniversalAdapterViewType.Content(
                R.layout.item_simple,
                listener = object : BasicListener<BasicModel> {
                    override fun onClick(model: BasicModel) {
                        Toast.makeText(this@BasicListingActivity, model.name, Toast.LENGTH_SHORT)
                            .show()
                    }
                })
        ).build()
    }
Enter fullscreen mode Exit fullscreen mode

Attach to adapter

binding.recyclerView.adapter = mAdapter.getAdapter()
Enter fullscreen mode Exit fullscreen mode

Update Data

mAdapter.updateData(Resource.success(list))
Enter fullscreen mode Exit fullscreen mode

Loading + Content + Error

example: Hitting an API for loading showing a shimmer and then when API response came to show the data or getting an error

Initialize Adapter

private val mAdapter by lazy {
        UniversalRecyclerAdapter.Builder<UserModel>(
            lifecycleOwner = this,
            content = UniversalAdapterViewType.Content(R.layout.item_user,
                object : BasicListener<UserModel> {
                override fun onClick(model: UserModel) {
                    Toast.makeText(this@LoadingListingActivity, model.name, Toast.LENGTH_SHORT)
                        .show()
                }
            }),
            loading = UniversalAdapterViewType.Loading(R.layout.layout_loading_full_page, defaultLoadingItems = 1),
            error = UniversalAdapterViewType.Error(R.layout.item_error)).build()
    }
Enter fullscreen mode Exit fullscreen mode

Attach to adapter

binding.recyclerView.adapter = mAdapter.getAdapter()
Enter fullscreen mode Exit fullscreen mode

Update Data

 mViewModel.data.observe(this, Observer { data -> 
     // The data type is like Resource<List<T>>
     // if data.status == Status.LOADING thenn it will show the loading view
     // if data.status == Status.SUCCESS then it will show the content list
     // if data.status == Status.ERROR then it will show the error View and data.message will be passed to view as message variable
            mAdapter.updateContent(it)
})
Enter fullscreen mode Exit fullscreen mode

Multiple View Types

Show multiple view types in your listing, for eg: heading and list

implement UniversalViewType in your model and override getLayoutId()

screenshot : view fullscreen

example :

Heading Model

data class HeadingModel(val title: String) : UniversalViewType,SchoolListing {
    override fun getLayoutId(): Int {
        return R.layout.item_heading
    }
}
Enter fullscreen mode Exit fullscreen mode

List Model

data class ListItemModel(val name: String) : UniversalViewType,SchoolListing {
    override fun getLayoutId(): Int {
        return R.layout.item_list
    }
}
Enter fullscreen mode Exit fullscreen mode

SchoolListing.kt

This interface is used to identify models to use in a recycler view, to prevent adding of other types of models in the array except for models that implements SchoolListing

interface SchoolListing
Enter fullscreen mode Exit fullscreen mode

Adding data to array

val tempArray = ArrayList<SchoolListing>()
        tempArray.add(HeadingModel("Principal"))
        tempArray.add(ListItemModel("Yogesh Paliyal"))

        tempArray.add(HeadingModel("Staff"))
        tempArray.add(ListItemModel("Sachin Rupani"))
        tempArray.add(ListItemModel("Suraj Vaishnav"))
        tempArray.add(ListItemModel("Himanshu Choudhan"))
        tempArray.add(ListItemModel("Pramod Patel"))
        tempArray.add(ListItemModel("Bharath"))
        tempArray.add(ListItemModel("Sanjay"))
        tempArray.add(ListItemModel("Surendra Singh"))


        tempArray.add(HeadingModel("Students"))
        tempArray.add(ListItemModel("Bhoma Ram"))
        tempArray.add(ListItemModel("Deepak"))
        tempArray.add(ListItemModel("Sohan"))
        tempArray.add(ListItemModel("Umesh"))
        tempArray.add(ListItemModel("Amanda Howard"))
        tempArray.add(ListItemModel("Jeremy Glover"))
        tempArray.add(ListItemModel("Ginger Larson"))
        tempArray.add(ListItemModel("Lincoln Pierpoint"))
        tempArray.add(ListItemModel("Brian Brooks"))
        tempArray.add(ListItemModel("Erasmus Hall"))
        tempArray.add(ListItemModel("Amber Lane"))
        tempArray.add(ListItemModel("Elsie Cole"))
Enter fullscreen mode Exit fullscreen mode

View full example

Feedback

Having an issue to get you are looking for, feel free to put your question in Discussion Section and help us Improving this library and Documentation.

Happy Coding 😁

Top comments (0)