Konveyor

Additional

Language
Kotlin
Version
0.5 (Sep 17, 2019)
Created
Jul 20, 2017
Updated
Sep 18, 2019 (Retired)
Owner
avito.tech (avito-tech)
Contributors
Dmitriy Voronin (dsvoronin)
Igor Solkin (solkin)
Daniil Popov (int02h)
Dmitry (dkostyrev)
Michael Casper (mcasper3)
Mikhail (fat-fellow)
Phil (philipuvarov)
7
Activity
Badge
Generate
Download
Source code

Advertisement

Overview

Konveyor is a tiny library which intends to battle RecyclerView.Adapter Hell by introducing "Composition over inheritance" approach when dealing with RecyclerView adapters. While making your Adapter related logic testable by providing abstraction layer over its logic, it will make you forget all of the ViewType hassle all together.

Contents

Installation

Gradle

Step 1. Add this in your root build.gradle

 allprojects {
  repositories {
   maven { url 'https://jitpack.io' }
  }
 }

Step 2. Add the dependency

 dependencies {
         compile 'com.github.avito-tech:Konveyor:VERSION'
 }

If you like to stay on the bleeding edge, or use certain commit as your dependency, you can use the short commit hash or anyBranch-SNAPSHOT as the version

Maven

 <dependency>
     <groupId>com.github.avito-tech</groupId>
     <artifactId>Konveyor</artifactId>
     <version>VERSION</version>
 </dependency>

Structure

Konveyor introduces set of key abstractions to extract knowledge about ids and view types away from RecyclerView.Adapter, thus, making all of the associated logic easily extensible and testable.

Item

Item is an interface that represents data associated with a certain ViewType:

class Dog(override val id: Long) : Item

id — identifier, that RecyclerView.Adapter will use in its methods.

ItemView

ItemView is an abstraction over RecyclerView.ViewHolder

interface DogView : ItemView {
    fun setName(name: String)
}

class DogViewHolder(view: View): BaseViewHolder(view), DogView {
    private val name = view.findViewById(R.id.name) as TextView

    override fun setName(name: String) {
        this.name.text = name
    }
}

Methods Overview

onUnbind() is called whenever RecyclerView.Adapter calls onViewRecycled() method for this ItemView. You can override this method in case you need, for example, unsubscribe from listeners or release some resources associated with this ViewHolder.

ItemPresenter

ItemPresenter connects Item and its view. Essentially, your implementation of the interface should contain everything you would normally do in onBindViewHolder() method of RecyclerView.Adapter

class DogPresenter: ItemPresenter<DogItemView, Dog> {

    override fun bindView(view: DogView, item: Dog, position: Int) {
        view.setName(item.name)
    }

}

ItemBlueprint

ItemBlueprint is a key entity that ties together Android world with our abstractions

class DogBlueprint(override val presenter: ItemPresenter<DogView, Dog>)
    : ItemBlueprint<DogView, Dog> {

    override val viewHolderProvider = ViewHolderBuilder.ViewHolderProvider(
                layoutId = R.layout.dog_item,
                creator = { _, view -> DogViewHolder(view) }
        )

    override fun isRelevantItem(item: Item): Boolean = item is Dog

}

Methods Overview

  • presenter — presenter associated with this view and data.
  • viewHolderProvider — class to create associated RecyclerView.ViewHolder
  • isRelevantItem(item: Item) — you have to override this method to build connection between given Item and its ItemBlueprint. Please mind, in the list of registered ItemBlueprints every check has to be unique. If multiple registered ItemBlueprints respond true to a given Item, ViewTypeCollisionException will be thrown.

AdapterPresenter

AdapterPresenter is an abstraction over RecyclerView.Adapter, that we can easily use in our unit tests. Current library provides default implementation for this interface - SimpleAdapterPresenter, this will satisfy 99.9% of your needs, unless you need something exotic.

Example

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val recycler = view.findViewById(R.id.recycler) as RecyclerView
        val binder = ItemBinder.Builder()
                        .registerItem(createDogBlueprint())
                        .registerItem(createCatBlueprint())

        val adapterPresenter = SimpleAdapterPresenter(binder, binder)
        recycler.adapter = SimpleRecyclerAdapter(adapterPresenter, binder)
    }

In most cases SimpleRecyclerAdapter, provided by this library will satisfy your needs.

This way you don't have to think about providing unique ViewTypes for your data, as ItemBinder will handle this for you.

Author

Philip Uvarov (philuvarov@gmail.com)

License

MIT