· 4 min read

Extension functions in Kotlin: Extend the Android Framework (KAD 08)

Extension functions are a really cool feature that Kotlin provides, and that you’ll find yourself using a lot when writing Android Apps.

We have to admit that the Android Framework sometimes makes things a bit difficult, and in Java, the only solution we have left is to create wrappers that do things as we want, or utility classes with static methods that are not the best in terms of readability.

How would you like to be able to add extra functions to the Framework classes? This is what the Kotlin extension functions allow us to do.

If you prefer, I recorded a video where I explain extension functions, but also lambdas with receivers: an extra concept that you will find exciting!

https://www.youtube.com/watch?v=dDJJXUi0IpQ

Extension functions in Kotlin

Extension functions are functions that, as the name implies, help us to extend the functionality of classes without having to touch their code. Now let’s see how these functions are defined, and some examples that I personally find very useful.

How can you define an extension function?

Just write a function as you would normally, and put the name of the class before separated by a point. These functions can be everywhere, usually in an Extensions file which doesn’t even need to contain a class.

Very simple example: we want to make a view have the visible(), which makes it visible. We would write something like this:

fun View.visible() {
    this.visibility = View.VISIBLE
}

I’ve written this so you can see that we can use the functions and properties of that class as if we were inside the class itself, but you can skip it:

fun View.visible() {
    visibility = View.VISIBLE
}

Some interesting examples

There are three examples that I like to explain because they perfectly show the power of extension functions.

The first one is how to create a Toast in an easy way. Instead of doing:

Toast.makeText(this@MainActivity, message, Toast.LENGTH_SHORT).show()

You could just do this, and encapsulate the complexity in an extension function:

toast(message)

...

fun Context.toast(message: String){
    Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}

The second is useful when you are inflating a view inside an adapter. Normally you would use something like this:

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
    val v = LayoutInflater.from(parent.context).inflate(R.layout.view_item, parent, false)
    return ViewHolder(v)
}

The line that inflates the view and uses parent is too complex, and 99% of the time is usually the same on any adapters. Why not give ViewGroups the ability to inflate views?

fun ViewGroup.inflate(layoutRes: Int): View {
    return LayoutInflater.from(context).inflate(layoutRes, this, false)
}

Now you can use it in the code above:

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
    val v = parent.inflate(R.layout.view_item)
    return ViewHolder(v)
}

A very similar example can be done with images. If you use the Picasso library, for example, you need to load the image using the typical builder:

Picasso.with(imageView.context).load(url).into(imageView)

How would you like to be able to tell ImageView to upload a URL by itself?

fun ImageView.loadUrl(url: String) {
    Picasso.with(context).load(url).into(this)
}

imageView.loadUrl(url)

Extension properties

Just as you can do extension functions, so can you do with properties. The only thing you need to remember is that extension properties cannot save state, but will need to use existing functions to request or modify the state of the object:

val ViewGroup.children: List<View>
    get() = (0..childCount - 1).map { getChildAt(it) }

This property retrieves the children of a ViewGroup.

Now you could iterate over them directly:

parent.children.forEach { it.visible() }

Note: it is a reserved word that is used to access the input value of the function, when there’s only one. As we have seen in other articles, you can name those input values, and write the left part of the lambda when there are more than one.

Conclusion

With extension functions and extension properties, you can extend any class (even if you don’t have access to the code) and then use those functions and properties as if they were part of the class. The only thing you will see is an extra import in the file where it’s used.

If you like what you’ve seen, I encourage you to sign up for my free training, where I’ll tell you everything you need to learn about how to create your own Android Apps in Kotlin from scratch.

    Share:
    Back to Blog