Reading Time: 12 minutes

In the name of God

Hey guys, welcome back to my blog.

In this episode, we are going to continue on the Epoxy series, expand our knowledge and try to make it even easier to implement lists on Android! since this is going to be part 2 if you have not checked out the first part make sure to have look there first. so without any further ado let’s get started.

In the last episode, we saw one way we could make an EpoxyModel class and feed it to our list. but that approach needed a KotlinModel class to be copied to our project because it’s not bundled in the epoxy library. another problem that approach has is that views defined using bind() delegate will be looked up again using findViewById() every time the bind function gets called, that means traversing the entire view every time which is not very efficient. so to overcome these problems there are a few ways provided out of the box.

before we talk about types of epoxy models we need to know a few semantics of them. each model has to have a unique ID. that means when you want to add the models to the EpoxyRecyclerView it’s ID  has to be set beforehand. you may use any type of primitives for your IDs but if you fear that Ids might collide you may use a string tag with them to separate them.

there is also an option of allowing Epoxy to generate Ids automatically for you. but we will get to that later.

when you call withModels() to bind new models or modify the old models Epoxy will look into equals and hashcode to check what has changed and apply the changes to that model accordingly if and only if new model and the previous one has the same id. in other words Epoxy is highly dependent on the ID that you provide to the models. make sure to keep IDs the same when you don’t want to recreate the entire list. to apply the changes you may override two-parameter
bind(T view, EpoxyModel<?> previouslyBoundModel) which gives you the previous model and you can check the difference and update the required parts.

the last thing about models is code-gen. Epoxy has a very powerful AnnotationProcessor which does quite a few things for us. The least it can do is generating models for you. If you want the help of EpoxyCode gen all you need to do is adding @ModelView annotation to your models. the generated classes will be postfixed with _ so that you know it’s been generated. since we are using Kotlin one more thing Epoxy code-gen does for us is generating extension function for each of our models. using the extensions will be more idiomatic and removes more boilerplate.

now with these in mind, we can discuss the types of models.

1. EpoxyModelWithHolder

this class is almost the same as RecyclerView.ViewHolder but it works with epoxy. this class is separated into two functions: bind/unbind and EpoxyHolder. as the name suggests EpoxyHolder is a class that holds your item Views. since we have a ViewHolder here the problem of finding views every time we bind is automatically gone. last but not least we have to override bind and unbind functions to bind the views in EpoxyHolder to the data for that Item.

If you are a ButterKnife user like me you may create a BaseEpoxyHolder (like the KotlinEpoxyHolder) and add Butterknife bind function in there so everyone extending your base class does not have to worry about binding views. (ain’t that cool?!).
with that, we can go to the next type of EpoxyModel

2. CustomViews

You can easily turn your customviews to an EpoxyModel. as I have said earlier all you need to do is just add @ModelView to your class. This annotation works in two ways. one way is Size enum to the annotation which tells epoxy code-gen the proper layout params to use when inflating your View.


the other (probably easier) way is to add defaultLayout and specify the layout XML file that needs to be inflated for this view (if you want to use this feature in a library project you need to add ButterKnife id generator processor to your project and use R2 instead of R). Again Epoxy code-gen will take care of everything to inflate and call the correct bind function for you plus an extension function on Controller to let you create and add a new model to the list. remember your layout XML file needs to have only one view as a parent and that view has to be your customview class.


There quite a several annotations you can use with @ModelView classes but I’ll explain only a few of them:

@TextProp: if you annotate your setter functions in model classes with this annotation the code-gen will generate these functions on the generated class aswell. so you can call them from outside of the generated model and set your CharSequence on your views.

@ModelProp: Almost the same as the previous one. this annotation tells Epoxy apt to generate required functions that allow you to set and bind any object (including String or UIModels) to your views. this annotation can also be used with properties. when the model is bound your property will be set.

@CallbackProp: This call back allows you to pass a click listener to your models. the reason this annotation is different from @ModelProp is that It generates another function on top of this which accepts OnModelClickListener. this interface will provide you with several arguments including a model current position on RecyclerView, your model instance, the view, and even the clicked view. so make sure to use this when setting listeners on your models

@OnViewRecycled: the last (but not least) annotation that I’m going to touch on today is onViewRecycled this annotation will allow you to get a callback whenever your model view has been recycled so you can clean up any reference or ongoing action to avoid leaks.


since we are creating our model using customview in Kotlin we need to tell the compiler to generate overloads for our view but this causes the Epoxy annotation processor to stop working. to fix this issue we need to create a config file for Epoxy AP to configure it for models in the same package. this file has to be named and it has to be in the same package as the model file. the config file will look like this:


Your final modelView will look like something like this:

and the generated model will be like this:

And the generated Extension for your model:

Finally, you may use this extension like this:

As you can see the APT does generate quite a long class for you.

Epoxy comes with a modelView out of the box it’s called: Carousel

This is one of the amazing features of Epoxy. since it’s out of the box and no configuration is needed. it allows you to quickly add views in a horizontal list in your verticals. it already has snap support and will snap views on user scroll.

You can easily customize the Carousel by extending it and create a new Carousel that does what you like. for example, if we want to disable the Snapping behavior we can create a new Carousel like this:

Again to use it:

With the tools that epoxy provides creating lists and lists in lists is easier than before. to be honest we are using epoxy in all of our screens even the ones that do not have any list in it.

As always you may find all the source codes on Github.

Thanks for reading and happy coding


Please enter your comment!
Please enter your name here