CellAdapter: a Simpler Way to Use RecyclerView

In terms of Android development, Adapter is a design pattern that separates business logic from view creation, handles mapping a bunch of data and dispatching updates to views.

Introduction

Displaying lists of data is a frequent functionality for most applications. Android SDK provides a developer with RecyclerView for showing a list of data. Often you can find a lot of different subclasses of RecyclerView.Adapter in one project: one adapter for each list presentation. This brings a lot of code duplication and increases probability of errors introduced by a developer due to copy-paste. Routinely, only the view layout and the data-to-view mapping differ from each other.

What is CellAdapter?

For the purpose of having our project code DRY, we've created CellAdapter. CellAdapter is a library used to simplify working with RecyclerView via a simple interface. It provides an opportunity to easily support multiple view types, to separate ViewHolders from Adapter class, map data to a view in a convenient way, to register and handle UI callbacks for each ViewHolder.

CellAdapter has 3 core classes components:

CellAdapter - the main adapter class, a subclass of RecyclerView.Adapter.

Cell - the main abstract view class for each type of data, a subclass of ViewHolder. Used to map data to a view.

Cell.Listener - nested Cell interface. It needs to be implemented to send callbacks from Cell.

Setup

Add the JitPack repository in your root build.gradle at the end of repositories:

How it works?

The example shows how easy it is to use CellAdapter with different data types. For detailed information, please review kotlin sample and/or java sample project on GitHub.

Model

First of all, let’s create a simple data class. There are no needs to extend some base objects: Cell class could work with any objects.

AlphaModel.kt

data classAlphaModel(val alpha: String)

Cell

The next step is to implement Cell for AlphaModel: AlphaCell needs to be extended from Cell class. CellAdapter library provides a special annotation (@Layout), which is used for declaring the view layout for each Cell.

Let's review Cell core methods:

bindView() - abstract method. Called each time when a view is recycled. In this method, a model data has to be set up to a view.

item() - returns an instance of a data object.

listener() - returns an instance of Cell callback. The callback can be Nullable if Cell.Listener wasn’t set.

Adapter

The main work is done. The only thing left is to create an adapter, register all cells, and fill the adapter with data.

The operations of creating an adapter and registering cells are pretty easy. CellAdapter provides a convenient approach for these operations. All you need is to specify classes of Cell and Model and provide a listener implementation if required.

private val adapter: CellAdapter = CellAdapter().let {

it.cell(AlphaCell::class) {

item(AlphaModel::class)

listener(object : AlphaCell.Listener {

override fun onPressOne(item: AlphaModel) {

showToast(String.format("%s%n press button %d", item.alpha, 1))

}

override fun onPressTwo(item: AlphaModel) {

showToast(String.format("%s%n press button %d", item.alpha, 2))

}

override fun onCellClicked(item: AlphaModel) {

showToast(item.alpha)

}

})

}

it.cell(BetaCell::class) {

item(BetaModel::class)

listener(object : BetaCell.Listener {

override fun onCellClicked(item: BetaModel) {

showToast(item.beta)

}

})

}

it.cell(GammaCell::class) {

item(GammaModel::class)

}

}

Now let’s set up RecyclerView and fill the adapter with data.

recycler_view.layoutManager = LinearLayoutManager(this)

recycler_view.adapter = adapter

for (i in 0..33) {

adapter.items.add(AlphaModel(String.format("AlphaModel %d", i)))

adapter.items.add(BetaModel(String.format("BetaModel %d", i)))

adapter.items.add(GammaModel(String.format("GammaModel %d", i)))

}

adapter.notifyDataSetChanged()

Selections

CellAdapter also has a built-in adapter implementation for single/multi selection lists - SelectableCellAdapter. All you need is to pass the desired SelectionManager to the SelectableAdapter constructor. Two managers have already been implemented: SingleSelectionManager and MultiSelectionManager. Feel free to create your own manager - extend SelectionManager class and implement your selection logic inside.

SelectionManager contains methods:

fun toggleSelection(position: Int)

fun setSelection(position: Int, isSelected: Boolean)

fun isSelected(position: Int): Boolean

fun clearSelections(notify: Boolean)

fun getSelectedItemCount(): Int

fun getSelectedPositions(): Collection<Int>

fun isSelected(position: Int): Boolean

SingleSelectionManager has additional methods:

fun getSelectedPosition(): Int

MultiSelectionManager has methods for bulk manipulations:

fun isAllSelected(): Boolean

fun setSelectedPositions(selectionPositions: List<Int>)

fun setSelectionForAll(isSelected: Boolean)

For selection, cell has to extend SelectableCell. Take a look at the example:

Thank you for reaching out to Sigma Software! Please fill the form below. Our team will contact you shortly.

Full Name *

E-mail *

Phone

Company

Message

Page url

I hereby confirm that I am familiar with
Sigma Privacy Policy and agree to the personal data provided by me being stored and processed in accordance with the Policy
*

Daniil

Senchugov

Android Developer

Daniil is an Android applications developer experienced with various Android and Java-related technologies. He has a wide range of projects completed: from small application prototypes to large enterprise systems working within team of up to 12 Android engineers.