Extension Functions | Advanced Kotlin Programming
So far in this lesson, you have learned about extension functions. You learned how using extension functions you could extend the functionality of classes you cannot otherwise modify. In this reading, you will find some examples of times when extension functions can prove useful.
🟢 ANDROID WITH MACHINE LEARNING! (COURSE)
🟢 KOTLIN INTERVIEW BOOTCAMP! (COURSE)
Introduction
As you’ve learned, extension functions help extend the functionality of classes you would not be able to modify otherwise. Extension functions also allow for more concise code, removing code duplication.
In the Android world, you will encounter many common extension functions that reduce code repetition and lead to shorter code.
Next, you will explore a few examples of such functions.
Presenting a toast to the user
You will often want to notify the user of something happening. A common mechanism for such notifications on Android is a toast. To present a toast to the user from a Fragment, for example, you would write code like this:
Toast.makeText(requireContext(), "Some message", Toast.LENGTH_SHORT).show()
If you have many toasts in your code, this adds up to a lot of code to maintain, especially if you want to change how toasts are displayed across the app. With an extension function, you can shorten this code:
fun Context.toast(message: String, length: Int = Toast.LENGTH_SHORT) {
Toast.makeText(this, message, length).show()
}
Now, to present a toast from an Activity, all you have to type is:
toast("Some message")
This works because once the extension function is imported, the receiver (Activity, in this case) is automagically derived by Kotlin.
Note how the original implementation looks when compared to the extension version
Toast.makeText(requireContext(), "Some message", Toast.LENGTH_SHORT)
.show()
toast("Some message")
As you can see, the extension version is dramatically shorter than the original implementation. A Fragment toast extension function can be implemented, too:
fun Fragment.toast(message: String, length: Int = Toast.LENGTH_SHORT) {
requireContext().toast(message, length)
}
This function delegates the work to the Context extension you saw earlier in this section, keeping the implementation of the presentation of a toast in one place and avoiding duplication. It allows you to present a toast from a fragment like so:
toast("Some message")
In the next section, you will find another useful extension.
Multiplying Strings
It can often prove useful to be able to repeat the same string multiple times. Would it not be nice if you could simply type Repeat * 3 and get Repeat RepeatRepeat as an output? Luckily, with an extension, you can:
operator fun String.times(count: Int): String {
val stringBuilder = StringBuilder()
repeat(count) {
stringBuilder.append(this)
}
return stringBuilder.toString()
}
operator is a special keyword in Kotlin. Combined with the times extension function, it tells Kotlin to translate the multiply symbol (*) in code to this extension function when the receiver and argument (String and Int in this example, respectively) match. So, with the above extension imported, Repeat * 3will indeed return RepeatRepeatRepeat. That’s convenient!
The last example you will explore has to do with adding new features support for users with older Android versions.
Supporting themes on older Android versions
Google provides developers with a library called Jetpack Core for supporting new features on older Android versions. One useful function included in Core is ResourcesCompat.getColor. It adds theme support when reading colors from resources. Retrieving a color using this function from an Activity looks like this:
ResourcesCompat.getColor(resources, R.color.color_name, theme)
That’s quite a lot to type or read repeatedly. With an extension function, you can reduce the boilerplate considerably:
fun Context.getColorCompat(@ColorRes colorResourceId: Int); Int {
return ResourcesCompat.getColor(this, colorResourceId, theme)
}
With the above extension function imported, to retrieve a color using the extension function, all you need to type is:
getColorCompat(R.color.color_name)
Isn’t that better? Here are both next to each other for comparison:
ResourcesCompat.getColor(resources, R.color.color_name, theme)
getColorCompat(R.color.color_name)
The extension version is almost half as long! A getColorCompat extension can be written for Views and Fragments too with similar results. Look at the toast example earlier in this reading to see how.
Concluding thoughts
Extension functions are great for writing concise code. They let you add functionality to classes you could otherwise not modify. They can also help make your code clearer and more maintainable. These are highly desirable traits for code, as you will find in your career as an Android developer.