Increasing productivity using Kotlin extension functions in Android.

vector created by upklyak — www.freepik.com

Android dev’s current love interest Kotlin has a really cool feature which can spare a lot of time by helping you skip writing redundant code every time. The feature is called as Kotlin Extensions. Kotlin supports both Extension functions and Extension properties. In this article we will be looking at the Extension functions. So what is an extension function? well, this function is sort of an extension of an existing class and has access to all its qualities but with a catch. When we are in need of a new functionality which derives itself from an existing class traditionally we will think about inheriting the class and creating our own functions. But here the process of creating new functions from an existing class is not done by directly inheriting the class instead we use a feature in Kotlin called Extensions. Instead of inheriting the the class we add our function to that class and this function in turn will have access to all the things within that class.But here is another catch the extensions do not actually modify the classes they extend.

By defining an extension, you do not insert new members into a class, but merely make new functions callable with the dot-notation on variables of this type” — Kotlin Documentation

The syntax will look like this “classObject.yourFunctionName(){}”

Let us look at a simple code snippet first. Let’s say we have a class called Hello. We have a function called getHello which returns a string called Hello. Now what if we want to get that string and attach another string “world” and make it “HelloWorld”. one way is to make another class and extend the Hello class but why go through the hassel when we have the Extension super power! How are we going to accomplish this without extending the class?.

class Hello()
{
fun getHello(): String
{
return “Hello”
}
}
fun main(){
fun Hello.addWorld(): String
{
return getHello()+”World”
}
val hello = Hello()
val helloworld = hello.addWorld()
println(helloworld)
}

What did we do in the above code. The answer lies within the main function.

we create a function from the class Hello which we have implemented like this

// Hello is the class and addWorld is the name of the extra functionality for the Hello class (it can be any name)
fun Hello.addWorld():String{
}

Now whenever we use an Object belonging to the Hello class we will be able to use the addWorld() functionality.

  val word = Hello() // instantiating a Hello object
val helloworld = word.addWorld() // using the addWorld() function
println(helloworld)

Output:

HelloWorld

The beauty is you can extend just about any class from user defined classes to libraries.

Now let’s do something cool using these extension functions in Android shall we ?

Another fun fact is we can do the same for the libraries in Android and not just on user defined classes. We are going to use existing android libraries to try and write some cool functions which can make our life as an android developer much simpler.

The code below is a snippet from creating a recycler adapter in android. Most of us might be using similar code everyday. And it is so tiring to keep repeating these lines. But what if there was a way to implement all this in one single line?

val linearManager = LinearLayoutManager(context)
linearManager.orientation = RecyclerView.HORIZONTAL
recyclerView.layoutManager = layoutManager

We could create an extension function to skip writing layout manager related code every time we create an adapter.

Our extension function will be using the RecyclerView class and adding a function name called setHorizontalLayoutManager (example)

fun RecyclerView.setHorizontalLayoutManager():
{
val linearManager = LinearLayoutManager(context)
linearManager.orientation = RecyclerView.HORIZONTAL
this.layoutManager = layoutManager
}

We use “this” to access the receiver object. Hence we access the recycler view layout manager with this.layoutManager.

Now whenever you create an adapter you can skip all those lines of code and write just

recyclerView.setHorizontalLayoutManager()
recyclerView.adapter = tasksAdapter

Wait ! If that is not enough to impress you. I have something more.

Let us now try something by combining the extension functions and higher order functions to achieve something cooler.

Let’s say we have an animation. I want to do something after the animation ends. The code below loads our animation and R.anim.slide_up is our animation.

val anim = AnimationUtils.loadAnimation(context, R.anim.slide_up)

Traditionally we would have done it this way. We would call the animation listener interface and attach it to our animation and then we would put the our code which is to be executed after the animation ends on the OnAnimationEnd callback of the animation listener.

var animListener = object : Animation.AnimationListener   {
override fun onAnimationRepeat(p0: Animation?) {

}

override fun onAnimationEnd(p0: Animation?) {
//do whatever you want to do after animation ends over here.
}

override fun onAnimationStart(p0: Animation?) {

}
}
anim.setAnimationListener(animListener)

Nothing is wrong here. But what if you wanted to use another animation in another class and want something else to happen at the end of that animation ? You are again going to write this entire implementation from scratch. Just think of all the redundancy and loss of productivity. But extension function is going to cut that crap for us. We are going to create a single set of code which can be reused whenever we want something to happen at the end of an animation. So we create an extension function called endWithAction.

We add this to the Animation class like this Animation.endWithAction(){}

Now we set the animation listener within this function along with all the callbacks. And since we want to pass the action which we want to get executed after our animation ends we will need to make this extension function also a higher order function and pass the action we want to perform as a block function. The below function represents the same.

fun Animation.endWithAction(block:() -> Unit):Animation{
setAnimationListener(object : Animation.AnimationListener {
override fun onAnimationRepeat(animation: Animation?) {
}

override fun onAnimationEnd(animation: Animation?) {
block()
}

override fun onAnimationStart(animation: Animation?) {
}
})
return this
}

Now we simply call the extension function and pass the action we want to perform within our higher order function as depicted below.

val anim = AnimationUtils.loadAnimation(context, R.anim.slide_up)
anim.endWithAction{
//you write your action here which will get executed when the animation ends.
}

To understand more about Higher order functions you can look at my previous article which i have dedicated for solely for Higher Order Functions. Now use your imagination and decide on the kind of extension function you want to implement to optimise your code and increase your productivity. Good luck.

https://thepranavjayaraj.medium.com/higher-order-functions-in-kotlin-e5f2cf72a76d

Software Engineer at FRND

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store