Convert Figma logo to code with AI

airbnb logoepoxy

Epoxy is an Android library for building complex screens in a RecyclerView

8,512
726
8,512
315

Top Related Projects

9,754

A modern JSON library for Kotlin and Java.

23,323

A Java serialization/deserialization library to convert Java Objects into JSON and back

9,077

Main Portal page for the Jackson project

25,732

FASTJSON 2.0.x has been released, faster and more secure, recommend you upgrade.

FlatBuffers: Memory Efficient Serialization Library

65,463

Protocol Buffers - Google's data interchange format

Quick Overview

Epoxy is an Android library for building complex screens in a RecyclerView. It simplifies the process of creating and managing complex, heterogeneous layouts by providing a declarative API and powerful data binding capabilities. Epoxy is designed to improve performance and reduce boilerplate code in Android applications.

Pros

  • Simplifies the creation of complex, dynamic layouts in RecyclerView
  • Improves performance through efficient view recycling and diffing
  • Provides a declarative API for easier code maintenance and readability
  • Supports data binding and view binding out of the box

Cons

  • Steep learning curve for developers new to the library
  • Requires additional setup and configuration compared to standard RecyclerView adapters
  • May introduce unnecessary complexity for simpler layouts
  • Limited documentation for advanced use cases

Code Examples

  1. Creating a simple EpoxyModel:
@EpoxyModelClass(layout = R2.layout.header_view)
abstract class HeaderModel(
    @EpoxyAttribute var title: String
) : EpoxyModelWithHolder<HeaderModel.Holder>() {

    override fun bind(holder: Holder) {
        holder.titleView.text = title
    }

    class Holder : EpoxyHolder() {
        lateinit var titleView: TextView

        override fun bindView(itemView: View) {
            titleView = itemView.findViewById(R.id.title)
        }
    }
}
  1. Building a list of models in an EpoxyController:
class MyController : EpoxyController() {
    override fun buildModels() {
        header {
            id("header")
            title("My Header")
        }

        for (item in items) {
            itemModel {
                id(item.id)
                title(item.title)
                description(item.description)
            }
        }
    }
}
  1. Using data binding with Epoxy:
@EpoxyModelClass(layout = R2.layout.item_view)
abstract class ItemBindingModel : EpoxyModelWithBinding<ItemViewBinding>() {
    @EpoxyAttribute lateinit var item: Item

    override fun bind(binding: ItemViewBinding) {
        binding.item = item
    }
}

Getting Started

To start using Epoxy in your Android project, add the following dependencies to your app's build.gradle file:

dependencies {
    implementation 'com.airbnb.android:epoxy:4.6.4'
    // Add for Kotlin support
    implementation 'com.airbnb.android:epoxy-kotlin:4.6.4'
    // Add for data binding support
    implementation 'com.airbnb.android:epoxy-databinding:4.6.4'
    // Add for annotation processor
    kapt 'com.airbnb.android:epoxy-processor:4.6.4'
}

Then, enable view binding in your app's build.gradle:

android {
    buildFeatures {
        viewBinding true
    }
}

Now you can start creating EpoxyModels and EpoxyControllers in your project.

Competitor Comparisons

9,754

A modern JSON library for Kotlin and Java.

Pros of Moshi

  • Lightweight and fast JSON parsing library specifically designed for Kotlin and Java
  • Supports custom type adapters for complex objects and polymorphic types
  • Seamless integration with Retrofit for network requests

Cons of Moshi

  • Limited to JSON serialization/deserialization, while Epoxy is a more comprehensive UI framework
  • Requires additional setup for Kotlin data classes compared to Gson
  • Less extensive documentation and community resources compared to Epoxy

Code Comparison

Moshi (JSON parsing):

val moshi = Moshi.Builder().build()
val jsonAdapter = moshi.adapter(User::class.java)
val user = jsonAdapter.fromJson(jsonString)

Epoxy (UI component building):

class UserEpoxyModel(
    @EpoxyAttribute var name: String,
    @EpoxyAttribute var email: String
) : EpoxyModelWithHolder<UserHolder>() {
    override fun bind(holder: UserHolder) {
        holder.nameView.text = name
        holder.emailView.text = email
    }
}

While both libraries serve different purposes, this comparison highlights the core functionality of each. Moshi focuses on efficient JSON parsing, while Epoxy provides a powerful framework for building complex, performant UI components in Android applications.

23,323

A Java serialization/deserialization library to convert Java Objects into JSON and back

Pros of Gson

  • Simpler and more lightweight, focusing solely on JSON serialization/deserialization
  • Easier to integrate into existing projects due to its focused functionality
  • More mature and widely adopted in the Java ecosystem

Cons of Gson

  • Limited to JSON processing, lacking UI component handling capabilities
  • Doesn't provide built-in support for Android-specific view binding or recycler view optimization
  • May require additional libraries or custom code for complex UI scenarios

Code Comparison

Gson (JSON parsing):

Gson gson = new Gson();
MyObject obj = gson.fromJson(jsonString, MyObject.class);
String json = gson.toJson(obj);

Epoxy (UI component handling):

@EpoxyModelClass
public abstract class HeaderModel extends EpoxyModelWithHolder<HeaderHolder> {
    @EpoxyAttribute String title;
    @Override
    public void bind(@NonNull HeaderHolder holder) {
        holder.headerView.setText(title);
    }
}

While Gson focuses on JSON processing, Epoxy is designed for building complex screens in Android applications. Gson is better suited for data serialization tasks, whereas Epoxy excels in creating and managing UI components, especially for RecyclerViews. The choice between the two depends on the specific requirements of your project.

9,077

Main Portal page for the Jackson project

Pros of Jackson

  • Widely adopted and mature JSON processing library for Java
  • Supports a broad range of data formats beyond JSON (XML, YAML, etc.)
  • Highly customizable with extensive annotation support

Cons of Jackson

  • Steeper learning curve due to its extensive feature set
  • Can be overkill for simple JSON parsing tasks
  • Requires more configuration for complex use cases

Code Comparison

Jackson (JSON parsing):

ObjectMapper mapper = new ObjectMapper();
MyPojo pojo = mapper.readValue(jsonString, MyPojo.class);

Epoxy (UI component building):

class MyEpoxyModel : EpoxyModelWithHolder<MyViewHolder>() {
    override fun bind(holder: MyViewHolder) {
        // Bind data to views
    }
}

Key Differences

  • Purpose: Jackson is primarily for data serialization/deserialization, while Epoxy focuses on building complex RecyclerView layouts in Android
  • Language: Jackson is Java-based (with Kotlin support), Epoxy is Kotlin-first
  • Scope: Jackson is a general-purpose library, Epoxy is specific to Android UI development

Use Cases

  • Jackson: API integration, data persistence, configuration management
  • Epoxy: Building complex, high-performance list UIs in Android applications

Both libraries excel in their respective domains, with Jackson being more versatile for data processing tasks and Epoxy optimizing Android UI development workflows.

25,732

FASTJSON 2.0.x has been released, faster and more secure, recommend you upgrade.

Pros of fastjson

  • High performance JSON parsing and serialization
  • Supports a wide range of Java objects and data types
  • Extensive configuration options for customization

Cons of fastjson

  • Less focus on UI components and view binding
  • Not specifically designed for Android development
  • Potential security vulnerabilities if not properly configured

Code Comparison

fastjson:

String jsonString = JSON.toJSONString(object);
MyObject obj = JSON.parseObject(jsonString, MyObject.class);

Epoxy:

class MyEpoxyModel : EpoxyModelWithHolder<MyViewHolder>() {
    override fun bind(holder: MyViewHolder) {
        // Bind data to views
    }
}

Summary

fastjson is a high-performance JSON library for Java, focusing on efficient serialization and deserialization. It offers extensive support for various data types and customization options.

Epoxy, on the other hand, is an Android library for building complex screens in a RecyclerView. It simplifies the process of creating and managing view holders, making it easier to build dynamic and efficient user interfaces.

While fastjson excels in JSON processing, Epoxy shines in UI component management and view binding for Android applications. The choice between the two depends on the specific needs of your project, whether it's primarily focused on data processing or UI development.

FlatBuffers: Memory Efficient Serialization Library

Pros of Flatbuffers

  • Cross-platform compatibility: Supports multiple programming languages
  • High performance: Offers zero-copy deserialization
  • Compact binary format: Efficient for storage and transmission

Cons of Flatbuffers

  • Steeper learning curve: Requires understanding of schema definition
  • Less flexibility: Schema changes can be more challenging
  • Limited built-in UI components: Focused on data serialization

Code Comparison

Epoxy (Android UI):

@EpoxyModelClass
abstract class HeaderModel : EpoxyModelWithHolder<HeaderHolder>() {
    @EpoxyAttribute lateinit var title: String
    
    override fun bind(holder: HeaderHolder) {
        holder.titleView.text = title
    }
}

Flatbuffers (Schema definition):

table Person {
  name:string;
  age:short;
  weight:float;
}

root_type Person;

Summary

Epoxy is an Android library for building complex RecyclerView layouts, while Flatbuffers is a cross-platform serialization library. Epoxy focuses on UI development, offering a declarative way to build dynamic lists. Flatbuffers, on the other hand, provides efficient data serialization across multiple platforms. The choice between them depends on the specific needs of your project: UI development (Epoxy) or efficient data serialization (Flatbuffers).

65,463

Protocol Buffers - Google's data interchange format

Pros of Protobuf

  • Cross-platform and language-agnostic serialization format
  • Highly efficient binary encoding for reduced data size and faster transmission
  • Strong typing and schema evolution support

Cons of Protobuf

  • Steeper learning curve compared to Epoxy's simpler API
  • Requires additional tooling and build process integration
  • Less focused on UI-specific use cases

Code Comparison

Protobuf (message definition):

message Person {
  string name = 1;
  int32 age = 2;
  repeated string hobbies = 3;
}

Epoxy (model definition):

@EpoxyModelClass
abstract class PersonModel : EpoxyModelWithHolder<PersonHolder>() {
  @EpoxyAttribute lateinit var name: String
  @EpoxyAttribute var age: Int = 0
  @EpoxyAttribute var hobbies: List<String> = emptyList()
}

While Protobuf focuses on data serialization and transmission, Epoxy is specifically designed for building complex RecyclerView layouts in Android. Protobuf offers a more versatile solution for cross-platform data exchange, while Epoxy provides a streamlined approach to UI development with its declarative API and automatic diff calculation for efficient updates.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

Build Status Maven Central GitHub license GitHub contributors

Epoxy

Epoxy is an Android library for building complex screens in a RecyclerView. Models are automatically generated from custom views or databinding layouts via annotation processing. These models are then used in an EpoxyController to declare what items to show in the RecyclerView.

This abstracts the boilerplate of view holders, diffing items and binding payload changes, item types, item ids, span counts, and more, in order to simplify building screens with multiple view types. Additionally, Epoxy adds support for saving view state and automatic diffing of item changes.

We developed Epoxy at Airbnb to simplify the process of working with RecyclerViews, and to add the missing functionality we needed. We now use Epoxy for most of the main screens in our app and it has improved our developer experience greatly.

Installation

Gradle is the only supported build configuration, so just add the dependency to your project build.gradle file:

dependencies {
  implementation "com.airbnb.android:epoxy:$epoxyVersion"
  // Add the annotation processor if you are using Epoxy's annotations (recommended)
  annotationProcessor "com.airbnb.android:epoxy-processor:$epoxyVersion"
}

Replace the variable $epoxyVersion with the latest version : Maven Central

See the releases page for up to date release versions and details

Kotlin

If you are using Kotlin you should also add

apply plugin: 'kotlin-kapt'

kapt {
    correctErrorTypes = true
}

so that AutoModel annotations work properly. More information here

Also, make sure to use kapt instead of annotationProcessor in your dependencies in the build.gradle file.

Library Projects

If you are using layout resources in Epoxy annotations then for library projects add Butterknife's gradle plugin to your buildscript.

buildscript {
  repositories {
    mavenCentral()
   }
  dependencies {
    classpath 'com.jakewharton:butterknife-gradle-plugin:10.1.0'
  }
}

and then apply it in your module:

apply plugin: 'com.android.library'
apply plugin: 'com.jakewharton.butterknife'

Now make sure you use R2 instead of R inside all Epoxy annotations.

@ModelView(defaultLayout = R2.layout.view_holder_header)
public class HeaderView extends LinearLayout {
   ....
}

This is not necessary if you don't use resources as annotation parameters, such as with custom view models.

Basic Usage

There are two main components of Epoxy:

  1. The EpoxyModels that describe how your views should be displayed in the RecyclerView.
  2. The EpoxyController where the models are used to describe what items to show and with what data.

Creating Models

Epoxy generates models for you based on your view or layout. Generated model classes are suffixed with an underscore (_) are used directly in your EpoxyController classes.

From Custom Views

Add the @ModelView annotation on a view class. Then, add a "prop" annotation on each setter method to mark it as a property for the model.

@ModelView(autoLayout = Size.MATCH_WIDTH_WRAP_HEIGHT)
public class HeaderView extends LinearLayout {

  ... // Initialization omitted

  @TextProp
  public void setTitle(CharSequence text) {
    titleView.setText(text);
  }
}

A HeaderViewModel_ is then generated in the same package.

More Details

From DataBinding

If you use Android DataBinding you can simply set up your xml layouts like normal:

<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable name="title" type="String" />
    </data>

    <TextView
        android:layout_width="120dp"
        android:layout_height="40dp"
        android:text="@{title}" />
</layout>

Then, create an interface or class in any package and add an EpoxyDataBindingLayouts annotation to declare your databinding layouts.

package com.airbnb.epoxy.sample;

import com.airbnb.epoxy.EpoxyDataBindingLayouts;

@EpoxyDataBindingLayouts({R.layout.header_view, ... // other layouts })
interface EpoxyConfig {}

From this layout name Epoxy generates a HeaderViewBindingModel_.

More Details

From ViewHolders

If you use xml layouts without databinding you can create a model class to do the binding.

@EpoxyModelClass(layout = R.layout.header_view)
public abstract class HeaderModel extends EpoxyModelWithHolder<Holder> {
  @EpoxyAttribute String title;

  @Override
  public void bind(Holder holder) {
    holder.header.setText(title);
  }

  static class Holder extends BaseEpoxyHolder {
    @BindView(R.id.text) TextView header;
  }
}

A HeaderModel_ class is generated that subclasses HeaderModel and implements the model details.

More Details

Using your models in a controller

A controller defines what items should be shown in the RecyclerView, by adding the corresponding models in the desired order.

The controller's buildModels method declares which items to show. You are responsible for calling requestModelBuild whenever your data changes, which triggers buildModels to run again. Epoxy tracks changes in the models and automatically binds and updates views.

As an example, our PhotoController shows a header, a list of photos, and a loader (if more photos are being loaded). The controller's setData(photos, loadingMore) method is called whenever photos are loaded, which triggers a call to buildModels so models representing the state of the new data can be built.

public class PhotoController extends Typed2EpoxyController<List<Photo>, Boolean> {
    @AutoModel HeaderModel_ headerModel;
    @AutoModel LoaderModel_ loaderModel;

    @Override
    protected void buildModels(List<Photo> photos, Boolean loadingMore) {
      headerModel
          .title("My Photos")
          .description("My album description!")
          .addTo(this);

      for (Photo photo : photos) {
        new PhotoModel()
           .id(photo.id())
           .url(photo.url())
           .addTo(this);
      }

      loaderModel
          .addIf(loadingMore, this);
    }
  }

Or with Kotlin

An extension function is generated for each model so we can write this:

class PhotoController : Typed2EpoxyController<List<Photo>, Boolean>() {

    override fun buildModels(photos: List<Photo>, loadingMore: Boolean) {
        header {
            id("header")
            title("My Photos")
            description("My album description!")
        }

        photos.forEach {
            photoView {
                id(it.id())
                url(it.url())
            }
        }

        if (loadingMore) loaderView { id("loader") }
    }
}

Integrating with RecyclerView

Get the backing adapter off the EpoxyController to set up your RecyclerView:

MyController controller = new MyController();
recyclerView.setAdapter(controller.getAdapter());

// Request a model build whenever your data changes
controller.requestModelBuild();

// Or if you are using a TypedEpoxyController
controller.setData(myData);

If you are using the EpoxyRecyclerView integration is easier.

epoxyRecyclerView.setControllerAndBuildModels(new MyController());

// Request a model build on the recyclerview when data changes
epoxyRecyclerView.requestModelBuild();

Kotlin

Or use Kotlin Extensions to simplify further and remove the need for a controller class.

epoxyRecyclerView.withModels {
        header {
            id("header")
            title("My Photos")
            description("My album description!")
        }

        photos.forEach {
            photoView {
                id(it.id())
                url(it.url())
            }
        }

        if (loadingMore) loaderView { id("loader") }
    }
}

More Reading

And that's it! The controller's declarative style makes it very easy to visualize what the RecyclerView will look like, even when many different view types or items are used. Epoxy handles everything else. If a view only partially changes, such as the description, only that new value is set on the view, so the system is very efficient

Epoxy handles much more than these basics, and is highly configurable. See the wiki for in depth documentation.

Documentation

See examples and browse complete documentation at the Epoxy Wiki

If you still have questions, feel free to create a new issue.

Min SDK

We support a minimum SDK of 14. However, Epoxy is based on the v7 support libraries so it should work with lower versions if you care to override the min sdk level in the manifest.

Contributing

Pull requests are welcome! We'd love help improving this library. Feel free to browse through open issues to look for things that need work. If you have a feature request or bug, please open a new issue so we can track it.

License

Copyright 2016 Airbnb, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.