Extension Functions and Properties in Kotlin
In this tutorial for Android, you’ll learn to use Kotlin extension functions and properties to extend the functionality of existing classes. By Rajdeep Singh.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Extension Functions and Properties in Kotlin
20 mins
Using Nullable Receivers
Everything you’ve learned about extension properties and extension functions also applies if the receiver is a nullable type. If the value of the variable is null, you can check for this == null
before doing any operation in the body.
In the next few steps, you’ll change the currentHand
in the MainActivity from type Hand
to type Hand?
. You’ll also make the necessary changes to the extensions to handle the nullable type.
Start by opening MainActivity. Above TODO: 15
, you’ll see the variable definition private lateinit var currentHand: Hand
.
Remove it and redeclare it as a nullable variable below TODO: 15
:
private var currentHand: Hand? = null
Remove currentHand = handsDb.getLoggedInHand()!!
above TODO: 16
and add the following snippet instead:
currentHand = handsDb.getLoggedInHand()
Also, replace showDescription
with the following:
private fun showDescription(hand: Hand?) {
binding.welcomeTv.text = getString(
R.string.welcome_username,
hand?.userName ?: "-"
)
binding.userDescriptionTv.text = getString(
R.string.user_description_total_fingers,
hand?.bio ?: "-", hand?.totalFingers
)
}
If hand
is null, it won’t show the value of the totalFingers
extension property. To fix this and print –, open Extensions.kt and replace the totalFingers
extension property with this:
val Hand?.totalFingers: String
get() {
if (this == null) return "-"
return (fingersCount + thumbsCount).toString()
}
You’ve changed the type to nullable and added a null check in the body. Now, your code can handle cases where currentHand
is null — for example, when a user who isn’t logged in is exploring the app.
Build and run. The app should run the same as before.
Defining Companion Object Extensions
Another helpful feature you can use is defining extension properties and functions for companion objects of classes. The syntax is the same as when you define extension properties for the classes themselves. For example, if you have a class Human
with a companion object like this:
class Human {
companion object {}
}
You can define an extension function for the companion object like this:
fun Human.Companion.greetOthers() {
println("Hello other humans")
}
You call extension functions on companion objects using only the class name, like Human.greetOthers()
.
Defining the Scope of Extensions
All the extensions you’ve defined are in the top level of Extensions.kt, directly under package. You can use the extensions anywhere in the project by importing them at the call site.
One of the good pratices to follow while working with extensions in a big project is to divide them in different files grouped by the receiver class. For example, all the extensions for ImageView
goes in one file and so on.
Most of the time, you’ll define extensions only at the top level, but you can also declare an extension for a class inside another class. In those cases, there are multiple implicit receivers.
The instance of the class inside which you declare the extension is the dispatch receiver and the instance of the class on which you define the extension is the extension receiver.
Open MainActivity and add the following snippet below TODO: 18
:
private fun Hand?.showGreeting() {
if (this == null) {
Toast.makeText(this@MainActivity, getString(R.string.greeting_anonymous),
Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(this@MainActivity, getString(R.string.greeting_user, userName),
Toast.LENGTH_SHORT).show()
}
}
This code adds an extension function showGreeting
on Hand
within MainActvity
. Here are a few things to understand about the code above:
- The scope of the extension is inside
MainActivity
only. That means that classes outsideMainActivity
can’t call the extension. - In case of name conflict between members of the dispatch and extension receivers, the extension receiver takes precedence. So in the code above, using the
this
keyword will refer to the instance ofHand
. - To refer to an instance of a dispatch receiver like
MainActivity
, the code use-qualified this syntax asthis@MainActivity
. - You can declare the extension as open instead of
private
so that subclasses ofMainActivity
can override it.
To call the extension you defined, add the following snippet under TODO: 19
:
currentHand.showGreeting()
Build and run the app. If you’re not logged in, login first and you’ll see a Toast
message in MainActivity
like this:
Congratulations, you’ve completed this tutorial!
Where to Go From Here?
You can download the final project using the Download Materials button at the top or bottom of this tutorial.
In this tutorial, you learned to use extension properties and functions.
If you want to learn more about them, check out Kotlin’s official extensions guide.
If you have any questions or comments, please join the discussion below.