Android Kotlin extensions RIP

Nav Singh
Nerd For Tech
Published in
4 min readNov 24, 2020

The Android Kotlin Extensions Gradle plugin almost 3 years ago brought two new conveniences to Android development in Kotlin:

Here we are not talking about KTX, it’s all about Android Kotlin Extensions Gradle plugin

Synthetics let you replace calls to

findViewById with kotlinx.android.synthetic bindings.
  • Parcelize allows you to remove boilerplate and easily create Parcelables through the @Parcelize annotation.

Major drawbacks of Kotlin synthetics

  • They pollute the global namespace
  • They don’t expose nullability information
  • They only work in Kotlin code

Replacement for Kotlin synthetics

Recommended approach that you should follow is ViewBinding

Let’s see step by step how we can migrate to viewBinding

// 1. step enable viewBinding
buildFeatures {
viewBinding true
}

Now rebuild your project and you are good to go: 💃

  • Now for all the layouts in your project respected dataBinding classes will be generated that you can find in the following path:
DataBinding generated classes folder path
  • Now we can use viewBinding in our respected activities and fragments:
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// old way to set the content
// setContentView(R.layout.activity_main)
binding = ActivityMainBinding.inflate(layoutInflater)

binding.tv.setOnClickListener {
// perform your action onClick

}
// get the root view from binding and set it to as ContentView.
setContentView(binding.root)
}
}
  • binding.root : It referes to the parentView of Layout

In case of fragments we need to manage the binding more carefully otherwise it might leads to unexpected memory leaks

  • Let’s see in case of fragments how we can use viewBindng:
class SampleFragment : Fragment() {

private var binding: FragmentSampleBinding? = null

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// Inflate the layout for this fragment
binding = FragmentSampleBinding.inflate(inflater, container, false)
return binding?.root!!
}

override fun onDestroyView() {
// we need to reset the binding to null once fragment's view get's destroyed which helps to avoid memory leaks

binding = null
super.onDestroyView()
}
}

Accessing included layouts:

  • Let’s check how we can access the views of included layouts :
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="64dp"
android:clickable="true"
android:focusable="true"
android:text="Hello World!"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/logo" />
<!-- in case of include, we must have to provide id tag to generate proper viewBinding variable which helps to access the views from included layout-->
<include
android:id="@+id/included"
layout="@layout/include_sample_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv" />

</androidx.constraintlayout.widget.ConstraintLayout>
  • Content of include_sample_layout:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
android:id="@+id/tv2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="64dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
  • Here is the sample of accessing tv2 from included layout :
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
binding.included.tv2.text = "Included textview"
setContentView(binding.root)
}
}

If you want to ignore any view from viewBinding or layout file you can do that by adding following properotes at appropriate levels in your layout file:

  • Ignore view from generating viewBinding : Don’t provide id property for view. ViewBinding will simply ignore that view.
<!-- the following view will be ignored by ViewBinding -->
<ImageView
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_margin="32dp"
android:importantForAccessibility="no"
android:src="@drawable/ic_launcher_background"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
  • Ignore the entire layout file : Add tools:viewBindingIgnore=”true” tag to the parent view of the layout file that you want to ignore by viewBinding generation
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:viewBindingIgnore="true"
tools:context=".MainActivity">

Replacement for Parcelize

  • In your respect module replace the old android-kotlin-extensions plugin with the new one which is specific to Parceable
plugins {
id 'kotlin-parcelize'
}

The kotlin-parcelize plugin provides a Parcelable implementation generator.

You need to use the following package for Parcelize 👇

// update all the imports from new package and you are good to go 💃
import kotlinx.parcelize

You should start using the standalone kotlin-parcelize plugin instead of android-kotlin-extensions.

--

--

Nav Singh
Nerd For Tech

Google Developer Expert for Android | Mobile Software Engineer at Manulife | Organizer at GDG Montreal