Engineering

Kotlin Delegates in Android - Real Life Examples

Kotlin delegates in Android - real life examples

As the Kotlin in Android application development has been officially supported for some time, many Android developers feel quite fluent and comfortable using this language. Nevertheless, there are always some new small things that we still discover in Kotlin, which is very exciting. Recently I’ve discovered such an exciting thing which was the usage of Kotlin delegate to solve some specific problem. So first of, let’s discuss the problem.

There is a very good media player library from Google which is called ExoPlayer. I bet that most of you have heard of it. Recently, they’ve added a very nice feature - support for Chromecast. Thanks to this feature, it is much easier to switch between a local media player and Chromecast. What they’ve actually done is creating a CastPlayer class and made it implement Player interface. The ExoPlayer class, which is meant for local playback, also implements Player interface. So now, we have two media players unified by Player interface. Sounds good as we can have one Player variable that holds reference to either a remote or a local player.

Inheritance diagram

As you’ve probably guessed, I had to create a video player that would support local playback and Chromecast. I wanted both ExoPlayer and CastPlayer to have some additional methods like loadMedia(playerMedia: PlayerMedia). My first thought was “Let’s use inheritance”, as simple as that. So I’ve created two classes VideoExoPlayer and VideoCastPlayer, where both implement ExtendedPlayer interface.

Inheritance diagram 2

Looks fine so far. Having a reference to ExtendedPlayer instance, we are able to access all the methods from Player interface and additional loadMedia() method.

But…nope :(

Take a look at VideoCastPlayer class

VideoCastPlayer

The CastPlayer class is final. We cannot inherit from it.

So if not inheritance then maybe…COMPOSITION. Right! As someone smart has said “Composition over inheritance” (probably it was Einstein).

So we can simply pass a CastPlayer instance as an argument and call methods we want on it. Here is how VideoCastPlayer class looks using composition.

VideoCastPlayer

Unfortunately, as ExtendedPlayer implements Player interface, we have to override all its methods. We don’t really want to do this as we’d like to keep implementations from CastPlayer class. Is there any solution to this?

Here comes the magic of Kotlin delagates! By using delegate we can implement all of Player interface methods using castPlayer instance given in constructor. Just check this out:

ExtendedPlayer

What we have done here is changing ExtendedPlayer from interface to abstract class, passing the player argument in constructor and letting this argument implement all the methods from Player interface using delegation. Pure magic, isn’t it?

As you can see in the picture below, there is no more error message that we have to implement Player interface methods.

VideoCastPlayer final

I think it is really worth having this superpower in your pocket.