Annotation Processing: Supercharge Your Development | Kodeco

Annotation processing is a powerful tool for generating code for Android apps. In this tutorial, you’ll create one that generates RecyclerView adapters.


This is a companion discussion topic for the original entry at https://www.kodeco.com/8574679-annotation-processing-supercharge-your-development

@gordan-glavas Thanks for this tutorial! :]

I saw that the generated PersonAdapter’s ViewHolder finds the views inside the bind() method:

class ViewHolder(
  itemView: View
) : androidx.recyclerview.widget.RecyclerView.ViewHolder(itemView) {
  fun bind(item: Person) {
    itemView.findViewById<TextView>(2131165330).text = item.name
    itemView.findViewById<TextView>(2131165248).text = item.address
  }
}

Instead, it’d better to find the views only once, when the ViewHolder is created, so I changed the AdapterCodeBuilder like this:

private fun TypeSpec.Builder.addViewHolderType(): TypeSpec.Builder = addType(
  ...
       .addSuperclassConstructorParameter("itemView")
       .addProperties()
       .addBindingMethod()
       .build()
)

private fun TypeSpec.Builder.addProperties(): TypeSpec.Builder = addProperties(
  data.viewHolderBindingData.map {
    PropertySpec.builder(it.fieldName, textViewClassName)
        .addModifiers(KModifier.PRIVATE)
        .initializer(
             "itemView.findViewById<%T>(%L)",
             textViewClassName,
             it.viewId
        )
        .build()
  }
)

private fun TypeSpec.Builder.addBindingMethod(): TypeSpec.Builder = addFunction(
  FunSpec.builder("bind")
      .addParameter("item", modelClassName)
      .apply {
          data.viewHolderBindingData.forEach {
              addStatement("%L.text = item.%L", it.fieldName, it.fieldName)
          }
      }
      .build()
)

Now, PersonAdapter’s ViewHolder looks like this:

class ViewHolder(
  itemView: View
) : androidx.recyclerview.widget.RecyclerView.ViewHolder(itemView) {
  private val name: TextView = itemView.findViewById<TextView>(2131165330)

  private val address: TextView = itemView.findViewById<TextView>(2131165248)

  fun bind(item: Person) {
    name.text = item.name
    address.text = item.address
  }
}