Kotlin Android Extensions

Learn about the Kotlin Android Extensions plugin from JetBrains that can help you eliminate much of the boilerplate code in your Android app. By Fernando Sproviero.

Leave a rating/review
Download materials
Save for later
Share

The Kotlin programming language has improved the Android development experience in many ways, especially since the announcement in 2017 of first-party support for the language. Null safety, extensions, lambdas, the powerful Kotlin standard library and many other features all add up to a better and more enjoyable way to make Android apps.

In addition to the Kotlin language, JetBrains also has developed a plugin for Android called the Kotlin Android Extensions, which was created to further ease everyday Android development. The extensions are a Kotlin plugin that every Android developer should be aware of.

In this tutorial, you’ll explore many of the features that come with the extensions, including the following main features:

View binding

View binding enables you to refer to views just like any other variable, by using synthethic properties, without the need to initialize view references by calling the ubiquitous findViewById().

Note: If you have used Butter Knife in the past, you’ll know that it also helps with view binding. However, the binding is done in a different way. Butter Knife requires you to write a variable and annotate it with the identifier of the corresponding view. Also, inside methods like Activity onCreate(), you need to call a method that will bind all those annotated variables at once. Using the Kotlin Android Extensions, you don’t need to annotate any variable. The binding is done the first time you need to access the corresponding view and saved into a cache. More on this later.

Note: If you have used Butter Knife in the past, you’ll know that it also helps with view binding. However, the binding is done in a different way. Butter Knife requires you to write a variable and annotate it with the identifier of the corresponding view. Also, inside methods like Activity onCreate(), you need to call a method that will bind all those annotated variables at once. Using the Kotlin Android Extensions, you don’t need to annotate any variable. The binding is done the first time you need to access the corresponding view and saved into a cache. More on this later.

LayoutContainer

The LayoutContainer interface allows you to use view binding with views such as the ViewHolder for a RecyclerView.

Parcelize annotation

The @Parcelize annotation saves you from having to write all the boilerplate code related to implementing the Parcelable interface.

Note: This tutorial assumes you have previous experience with developing for Android in Kotlin. If you are unfamiliar with the language, have a look at this tutorial. If you’re beginning with Android, check out some of our Getting Started and other Android tutorials.

Note: This tutorial assumes you have previous experience with developing for Android in Kotlin. If you are unfamiliar with the language, have a look at this tutorial. If you’re beginning with Android, check out some of our Getting Started and other Android tutorials.

Getting started

The project you’ll be working with, YANA (Yet Another Notepad App), is an app to write notes. Use the Download Materials button at the top or bottom of this tutorial to download the starter project.

Once downloaded, open the starter project in Android Studio 3.0.1 or greater, and give it a build and run. Tap the floating action button to add a note, and tap the back button to save a note into your list.

Taking a look at the project, you see that it consists of two activities:

  • NoteListActivity.kt: The main activity that lists all your existing notes and lets you create or edit one.
  • NoteDetailActivity.kt: This will show an existing note and also can handle a new note.

Setting up Kotlin Android Extensions

Open the build.gradle file for the app module and add the following, just below the ‘kotlin-android’ plugin:

apply plugin: 'kotlin-android-extensions'

That’s all the setup you need to use the plugin! Now you’re ready to start using the extensions.

Note: If you create a new Android app with Kotlin support from scratch, you’ll see that the plugin is already included in the app build.gradle file.

Note: If you create a new Android app with Kotlin support from scratch, you’ll see that the plugin is already included in the app build.gradle file.

View binding

Open NoteListActivity, and remove the following lines from the onCreate method:

val noteListView: RecyclerView = findViewById(R.id.noteListView)
val addNoteView: View = findViewById(R.id.addNoteView)

Android Studio should notice that it’s missing imports for your two views. You can hit Option-Return on macOS or Alt-Enter on PC to pull in the imports. Make sure to choose the import that starts with kotlinx to use the extensions.

If you check the imports now at the top of the file, you should see the following:

import kotlinx.android.synthetic.main.activity_note_list.*

In order to generate the synthetic properties, to reference the views of the layout, you need to import kotlinx.android.synthetic.main.<layout>.*. In this case, the layout is activity_note_list. The asterisk wild-card at the end means that all possible views will be pulled in from the file. You can also import views individually if you wish, by replacing the asterisk with the view name.

Your `onCreate()` method should now look like this:


override fun onCreate(savedInstanceState: Bundle?) {

    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_note_list)
    
    noteRepository = ...
    
    adapter = ...
    
    // 1
    noteListView.adapter = adapter
    // 2
    addNoteView.setOnClickListener {
      addNote()
    }
  }
  1. To reference the list that shows notes, check the `id` in the activity_note_list.xml file, you’ll find that it’s noteListView. So, you access it using noteListView.
  2. The floating action button has the `id` addNoteView, so you reference it using addNoteView.

It’s important to note here that your synthetic view reference has the same name as the `id` you used in the layout file. Many teams have their own naming conventions on XML identifiers, so you may need to update your convention if you want to stick to camel case on the view references in your code.

Next, open NoteDetailActivity and remove the following view properties:

private lateinit var editNoteView: EditText
private lateinit var lowPriorityView: View
private lateinit var normalPriorityView: View
private lateinit var highPriorityView: View
private lateinit var urgentPriorityView: View
private lateinit var noteCardView: CardView

Also, remove the findViewById calls in onCreate().

The project will not compile at this point because all of those undeclared views. However, if you take a look into the view ids of activity_note_detail.xml and note_priorities_chooser_view.xml, you’ll notice they match the undeclared views you have in the activity. Add the following imports to the top of the file:

import kotlinx.android.synthetic.main.activity_note_detail.*
import kotlinx.android.synthetic.main.note_priorities_chooser_view.*

Now the project should compile again :]

Finally, do similar with NoteListAdapter, and remove the following in NoteViewHolder:

private val noteTextView: TextView = itemView.findViewById(R.id.noteTextView)
private val noteDateView: TextView = itemView.findViewById(R.id.noteDateView)
private val noteCardView: CardView = itemView.findViewById(R.id.noteCardView)

Add the following import to the file:

import kotlinx.android.synthetic.main.note_item.view.*

Note: in a view you have to import kotlinx.android.synthetic.main.<layout>.view.*

Note: in a view you have to import kotlinx.android.synthetic.main.<layout>.view.*

And then prepend each referenced view with itemView, like so:

fun bind(note: Note, listener: Listener) {
  itemView.noteTextView.text = note.text
  itemView.noteCardView.setCardBackgroundColor(
    ContextCompat.getColor(itemView.noteCardView.context, note.getPriorityColor()))
  itemView.noteCardView.setOnClickListener {
    listener.onNoteClick(itemView.noteCardView, note)
  }

  itemView.noteDateView.text = sdf.format(Date(note.lastModifed))
}

Build and run the app, and you’ll see that everything is working like before, and you’ve removed all the findViewById() boilerplate. :]