Kotlin Delegates in Android: Take advantage of the power of delegated properties in Android development

Tram Ho

Kotlin is really a beautiful language with some great features that make application development an enjoyable experience. One such feature is delegated properties. In this post, we will see how delegates can make our lives easier to develop Android.

Basic concept

First of all, what is a delegate and how does it work? It seems like some kind of magic but it’s really not that complicated. A delegate is just a class that provides value to an attribute and handles its changes. This allows us to move or delegate the getter-setter logic from the property itself to a separate class, allowing us to reuse this logic.

Suppose we want a String attribute parameter to always have a truncated string, i.e. with leading whitespace and a trailing checkmark removed. We can do this in the attribute setter like this:

Now, what if we want to reuse this function in some other class? Here, where delegates are used:

So a delegate is just a class with two methods: get and set the value of an attribute. To give it some more information, it is provided with the property it works with via the Instance of the KProperty class and an object with this property via thisRef . And here is how we can use this newly created delegate:

The equivalent of this:

:: param is the operator returns an instance of the class attribute KProperty. As you can see, there’s no mystery about delegates. But although simple, they can be very helpful. So let’s look at some examples, specific to Android.

Fragment arguments

We often need to pass some parameters to a fragment. It usually looks like this:

We pass parameters when creating a fragment via its static newInstance method. Inside it, we put parameters into the Fragment arguments to get them later in onCreate. We can make the code a bit nicer, moving logic related arguments to Getters and setters properties:

But basically we still have to write the same code for each attribute, which can be a chore if we have many of them. Besides, it seems a bit messy with all this explicit work with arguments. So is there a way to beautify the code?

The answer is yes! We will use the property delegates. First, the fragments arguments are stored in a Bundle object, with separate methods for setting different value types. So create an extension function that tries to put an arbitrary type value into the package and throws an exception if the type is not supported.

We are now ready to create a delegate for it:

Delegates read property values ​​from fragment arguments. And when the attribute value changes, Delegate will access fragment arguments (or create and set a new Bundle as an argument if the fragment does not already have them), then write a new value for these arguments, using the open function. Bundle.put width that we have created before.

ReadWriteProperty a common interface to accept two types of parameters. We set the first one as fragment, making this Delegate available only for properties within a fragment. This allows us to access the fragment instance with thisRef and manage its arguments.

Note that we use the name of the property as the key for the argument, so we don’t have to store keys as constants anymore. The second type parameter of ReadWriteProperty determines which value type the attribute can have. We set the type to non-nullable and throw an exception if the value cannot be read. This allows us to have non-nullable properties in fragments, avoiding us from nasty null checks. But sometimes we need a property that is null. So let’s create another Delegate, if no arguments are found, don’t throw an exception, but return null instead:

Next, let’s make some convenient functions (unnecessary, purely for aesthetic purposes):

Finally, put delegates to use:

Looks pretty neat, right?

Continue

Share the news now

Source : Viblo