example extensions

The power of Kotlin extension functions

Developing Android applications with Kotlin is a great experience even without using libraries and relying only on the Android SDK. But why wouldn't you try to make it better?

A world before Kotlin

Before Kotlin if we wanted to smoothen out the edges of the Android SDK, we usually did it with inheritance. We created subclasses and added extra methods and fields to the parents. It looked like this:

public class TurboImageView extends ImageView {
  public TurboImageView(final Context context) {
    super(context);
  }
  public void loadUrl(String url) {
    // Download the image
  }
}

But there are a few problems with this approach:

  • Composition over inheritance is a principle in object oriented programming. Its main idea is that classes should achieve polymorphic behavior and code reuse by containing instances of other classes rather than inheriting from a parent class. In Java there is no multiple inheritance (nor in Kotlin) which protects us programmers from making a great mess, but it also makes hard to e.g. mix the functionality of TurboImageView with ZoomImageView into one AwesomeImageView class.
  • Using custom types instead of what the Android SDK provides is sometimes inconvenient. You have to write more code to make place for subclasses instead of just using the regular ImageView. You and everyone working on a project have to keep in mind what kind of special class fits the current requirement.

Extension functions

These troubles vanish when we start using Kotlin extension functions. With this feature, you can glue new methods to an existing type without introducing inheritance. Although it's important to say that you can only access public methods and fields (because extensions are resolved statically) but when making shortcuts and designing new interfaces to interact with the SDK, it really makes a difference.

Let's see how it's done:

fun ImageView.loadUrl(url: String) {
  // Download the image
}

That's it. Move this file where you defined this function from project to project, or create a library with a collection of other helper functions. After that every simple ImageView will be capable of downloading an image. Isn't that great?

Snackbar extensions

Let's check out the possibilities with a real world example: the Snackbar. It was added to Android Support Library a few years ago to replace Toast that served well for a long time as a messaging interface between the user and the app. It solved a few issue and introduced a fresh look but for 90% of the time using its API is adding unnecessary complexity to our code. We don't want to define every time how long we want to show the message. Nor the place where it should appear. After filling a bunch of parameters why do we have to call another method, show()? We already wrote a lot about the Anko library. You can check it out here and here. Anko has it's helper functions for the Snackbar which makes it easier to use and make the code more concise:

snackbar(parentView, "message")

But why stop there if we can make it even shorter? For most cases, the only parameter we need is the message. So our aim is the achieve this:

snackbar("message")

We only need to eliminate the view parameter and because we want to show our message appearing at the bottom of the screen, fortunately, we can do just that. Getting the root view in an activity can be done by using the find(android.R.id.content) line. The extension method for the Activity will look like this:

inline fun Activity.snackbar(message: String) = snackbar(find(R.id.content), message)

Where else do we want to use Snackbar usually? Of course the other two main components of the Android UI: in Fragments and in Views. In a Fragment class, we have a reference for the Activity where it resides. So it couldn't be easier to extend our solution:

inline fun Fragment.snackbar(message: String) = snackbar(activity.find(R.id.content), message)

In case of Views, we need to be clever. A View not necessarily attached to an Activity. Before we try to show a Snackbar we have to make sure that the View's context property hides an Activity instance:

inline fun View.snackbar(message: String) {
  val activity = context
  if (activity is Activity) snackbar(activity.find(android.R.id.content), message)
  else throw IllegalStateException("View needs to be attached to an Activity.")
}

Let's write libraries!

That's all. We covered the main areas where we usually want to show a Snackbar. Our solution fits most of the use cases we face in a simple project. Using Kotlin extension functions to make the Android SDK more developer friendly is super easy. With a few lines of code (and of course with the help of Anko) we transformed our code from this:

Snackbar.make(view, "message", Snackbar.LENGTH_SHORT).show()

To this:

snackbar("message")

Are you tired of using the ContextCompat.getColor(context: Context, resId: Int) every time you want to get a color programatically? Write a colorFromResId(resId: Int) extension function to classes where you have access to a Context instance. The possibilites are endless. I'm sure you already have many great ideas with extensions. Don't hesitate! Start to develop libraries for Android with Kotlin!

If you need ideas for a new library check out what the community already did it on kotlinresources.com.