Kotlin Version of One Recycler View Adapter for All*

Ever since Kotlin became a first class language for Android, I have not gone a day without hearing, reading or watching something about Kotlin. Not as if I do it intentionally — I just cant avoid it. Its just everywhere.

Ever since Kotlin became a first class language for Android, I have not gone a day without hearing, reading or watching something about Kotlin. Not as if I do it intentionally — I just cant avoid it. Its just everywhere. So I revisited my first story on medium, and well its Java 7(Yeah it is). Then I got a bright idea, why don’t I just Kotlinize() that article for my next story.

Lets begin!

public CardObject(String title, String subtitle, String image, String info){
this.title = title;
this.subtitle = subtitle;
this.image = image;
this.info = info;

This is the CardObject Class I created in Java 7. Well the Kotlinized version of this class is

data class CardObject(val title: String, val subtitle: String, val image: String, val info: String) {


The Kotlin version is kind of neat. Its short and straightforward. You don’t need to do any setters and getters. Read more about data classes here.

public CardListPackage(String cardType, ArrayList<CardObject> cardObjects, int cardXML) {
this.cardType = cardType; //type of data eg students,courses etc
this.cardObjects = cardObjects; //data for the recycler view
this.cardXML = cardXML; //xml associated to this card type

The CardListPackage is also similar

data class CardListPackage(val cardType:String,val cardObjects:List<CardObject>,val cardXML:Int) {

Well isn’t this sweet!

You remember our Java 7 recycler view adapter….yeah I do. It was one great class.

public CardObjectAdapter(Context context, CardListPackage cardListPackage,CardBindingListener cardBindingListener, CardTappedListener cardTappedListener) {
this.context = context;
this.cardObjects = cardListPackage.getCardObjects();
this.card_xml = cardListPackage.getCardXML();
this.cardType = cardListPackage.getCardType();

this.cardTappedListener = cardTappedListener;
this.cardBindingListener = cardBindingListener;
public CardObjectViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(card_xml, viewGroup, false);
CardObjectViewHolder cardObjectViewHolder = new CardObjectViewHolder(view,cardType);
return cardObjectViewHolder;
public void onBindViewHolder(final CardObjectViewHolder cardObjectViewHolder, final int position) {

cardObjectViewHolder.cardObject = cardObjects.get(position);
final CardObject cardObject = cardObjects.get(position);
try {
} catch (Exception e) {
Log.e("error", e.toString());

public int getItemCount() {
return cardObjects.size();
public class CardObjectViewHolder extends RecyclerView.ViewHolder {

//simple views
public TextView title, subtitle, info;
public ImageView image;
public CardObject cardObject;
public int position;
//you can put more views here
public View border,parentCard;
public CardObjectViewHolder(final View card,String cardType) {

parentCard = card;
title = (TextView) parentCard.findViewById(R.id.title);
image = (ImageView) parentCard.findViewById(R.id.image);
subtitle = (TextView) parentCard.findViewById(R.id.subtitle);
info = (TextView) parentCard.findViewById(R.id.info);

cardObjectPresenter = new CardObjectPresenter(context,cardType,this);


card.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {

Can Kotlin suprise as this time?

class CardObjectAdapter(val context: Context, cardListPackage: CardListPackage,
val cardBindingListener: (CardObject, CardObjectViewHolder, Int) -> Unit,
val cardTappedListener: (CardObject) -> Unit
) : RecyclerView.Adapter<CardObjectAdapter.CardObjectViewHolder>() {

var cardObjects: List<CardObject>
var card_xml: Int = 0
var lastPosition = -1
var animationXml = 0
var cardType: String

init {
this.cardObjects = cardListPackage.cardObjects
.card_xml = cardListPackage.cardXML
.cardType = cardListPackage.cardType


override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): CardObjectViewHolder {
val view = LayoutInflater.from(viewGroup.context).inflate(card_xml, viewGroup, false)
val cardObjectViewHolder = CardObjectViewHolder(view, cardType)
return cardObjectViewHolder

override fun onBindViewHolder(cardObjectViewHolder: CardObjectViewHolder, cardPosition: Int) {

cardObjectViewHolder.cardObject = cardObjects[cardPosition]
val cardObject = cardObjects[cardPosition]
try {
cardObjectViewHolder.title.text = cardObject.title
cardObjectViewHolder.subtitle.text = cardObject.subtitle
cardObjectViewHolder.info.text = cardObject.info
} catch (e: Exception) {
Log.e("error", e.toString())

cardBindingListener(cardObject, cardObjectViewHolder, cardPosition)

setAnimation(cardObjectViewHolder.container, cardPosition)

override fun getItemCount(): Int {
return cardObjects.size

inner class CardObjectViewHolder(var parentCard: View, cardType: String) : RecyclerView.ViewHolder(parentCard) {

//simple views
var title: TextView
var subtitle: TextView
var info: TextView
var container: LinearLayout
var cardObject: CardObject? = null
var image
: ImageView
var cardPosition: Int = 0

//for more complex views
var border: View? = null
var cardObjectPresenter
: CardObjectPresenter

init {
title = parentCard.findViewById(R.id.title) as TextView
image = parentCard.findViewById(R.id.image) as ImageView
subtitle = parentCard.findViewById(R.id.subtitle) as TextView
info = parentCard.findViewById(R.id.info) as TextView
container = parentCard.findViewById(R.id.container) as LinearLayout
cardObjectPresenter = CardObjectPresenter(context, cardType, this)

parentCard.setOnClickListener { cardTappedListener(cardObject!!) }

A few surprises though.

val cardBindingListener: (CardObject, CardObjectViewHolder, Int) -> Unit,
val cardTappedListener: (CardObject) -> Unit

We replace the listeners with these lambda definitions. So when the constructor of the CardObjectAdapter is called it will expect two lambdas which conform to this signature.

/*This implies that if cardObject is null, a Null Pointer Exception will be thrown. For further explanation, please go here.

Our CardObjectPresenter Looked liked this

public CardObjectPresenter(Context context, String cardType, CardObjectAdapter.CardObjectViewHolder cardObjectViewHolder) {
this.context = context;
this.cardObjectViewHolder = cardObjectViewHolder;
this.cardType = cardType;
//used to find extra references apart from the basic //title,subtitle,image and infopublic void findCardReferences() {
switch (cardType.toLowerCase()) {
case "students":
cardObjectViewHolder.border = cardObjectViewHolder.parentCard.findViewById(R.id.border);
//more cases here ...
data class CardObjectPresenter(val context:Context,val cardType:String,val cardObjectViewHolder: CardObjectAdapter.CardObjectViewHolder) {

fun findReferences(){
when (cardType) {
"students" -> cardObjectViewHolder.border = cardObjectViewHolder.parentCard.findViewById(R.id.border)
/*"teachers" -> cardObjectViewHolder.border = cardObjectViewHolder.parentCard.findViewById(R.id.border)
more cases here*/
else -> {
print("x is neither 1 nor 2")

So in Kotlin the When keyword replaces the switch keyword in Java. Its great so read more on it here.

And how about our java interfaces?

public interface CardBindingListener {
void onCardBinding(CardObject cardObject, CardObjectAdapter.CardObjectViewHolder cardObjectViewHolder,int position);
public interface CardTappedListener {
public void onCardTapped(CardObject cardObject);

Well they now look like this …

// Its empty because we don't need interfaces to do this 
// we used the lambda's to achieve that!

So finally how do we use this. In the first story, this is how we did it

final int cardSize = cardObjects.size();
CardListPackage cardListPackage = new CardListPackage("students",cardObjects,R.layout.student_card);
cardObjectAdapter = new CardObjectAdapter(context, cardListPackage, new CardBindingListener() {
public void onCardBinding(CardObject cardObject, CardObjectAdapter.CardObjectViewHolder cardObjectViewHolder, int position) {
if (position == cardSize - 1) {//the extra view for the student card cardObjectViewHolder.border.setBackgroundColor(context.getResources().getColor(R.color.white));
}, new CardTappedListener() {
public void onCardTapped(CardObject cardObject) {
Intent intent = new Intent(context, StudentProfile.class);
intent.putExtra("card_id", cardObject.getId());

In Kotlin, this is how I used it

val card_objects = findViewById(R.id.card_objects) as RecyclerView;
card_objects.layoutManager = LinearLayoutManager(context)

val cardObjects:List<CardObject> = List(10){index -> CardObject("Teacher $index","Teachers Name","http://image.com","More info about teacher")}
cardListPackage = CardListPackage("simple",cardObjects,R.layout.simple_list);

card_objects.adapter = CardObjectAdapter(context,cardListPackage,cardBindingListener = {
cardObject,cardViewHolder,position ->

,cardTappedListener = {cardObject ->
intent = Intent(context,MainActivity::class.java)
intent.putExtra("card_id", cardObject.title)

Wheeew! we are done now. I hope this has been helpful. Kotlin is a great language. Its fun, modern and flexible. If you are doing native android with Java then learning Kotlin will be fun and refreshing. Give a try today. After all more knowledge never hurts. Have a great day.

Software Engineer with great love for Mathematics especially Abstract Mathematics.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store