• No results found

Standard Delegates

In document Kotlin for Android Developers (Page 81-85)

III. About the author

16.3 Standard Delegates

You can find a set of standard delegates included in the Kotlin standard library. These are the most common situations where a delegate is really useful, but we could also create our own.

Lazy

It takes a lambda that is executed the first timegetValueis called, so the initialisation of the property is delayed up to that moment. Subsequent calls will return the same value. This is very interesting for things that are not always necessary or require some other parts to be ready before this one is used. We can save memory and skip the initialisation until the property is required.

16 Application Singleton and Delegated Properties 73

1 class App : Application() {

2 val database: SQLiteOpenHelper by lazy { 3 MyDatabaseHelper(applicationContext)

4 }

5

6 override fun onCreate() {

7 super.onCreate()

8 val db = database.writableDatabase

9 }

10 }

In this example, the database is not really initialised until it’s called first time in onCreate. At that moment, we are sure the application context exists and is ready to be used. Thelazyoperation is thread safe.

You can also uselazy(LazyThreadSafetyMode.NONE) { ... }if you’re not worried about multi-threading and want to get some extra performance.

Observable

This delegate will help us detect changes on any property we need to observe. It will execute the declared lambda expression every time thesetfunction is called. So after the new value is assigned, we receive the delegated property, the old value and the new one.

1 class ViewModel(val db: MyDatabase) { 2

3 var myProperty by Delegates.observable("") { 4 _, _, new ->

5 db.saveChanges(this, new)

6 }

7

8 }

This example represents some kind ofViewModelclass which is aware ofmyProperty changes, and saves them to the database every time a new value is assigned.

16 Application Singleton and Delegated Properties 74

Underscores for unused parameters

Since Kotlin 1.1, you can use underscores to avoid giving a name to a lambda argument that you won’t use. This is nice, because it helps both the compiler and the reader. The compiler won’t need to save memory for variables that are not being used, and the reader won’t need to parse which parameters are being used and discard the ones that are not.

Vetoable

This is a special kind of observable that lets you decide whether the value must be saved or not. It can be used to check some conditions before saving a value.

1 var positiveNumber = Delegates.vetoable(0) { 2 _, _, new ->

3 new >= 0

4 }

The previous delegate will only allow the new value to be saved if it’s a positive number. Inside lambdas, the latest line represents the return value. You don’t need to use thereturnword (it won’t compile indeed).

lateinit

Sometimes we need something else to initialise a property, but we don’t have the required state available in the constructor, or we are even not able to access to them.

This second case happens now and then in Android: in activities, fragments, services, broadcast receivers… However, a non abstract property needs a value before the constructor finishes executing. We cannot just wait until we want, in order to assign a value to the property. We have at least a couple of options.

The first one is to use a nullable type and set it to null, until we have the real value.

But we then need to check everywhere throughout the code whether the property is null or not. If we are sure this property won’t be null the first time we use it, this may make us write some unnecessary code.

16 Application Singleton and Delegated Properties 75 The second option is to uselateinit, which identifies that the property should have a non-nullable value, but its assignment will be delayed. If the value is requested before it is assigned, it will throw an exception that clearly identifies the property being accessed.

lateinitis not exactly a delegate, but a property modifier, and that’s why it must be written before the property.

This could be helpful in the App singleton example:

1 class App : Application() { 2

3 companion object {

4 lateinit var instance: App

5 }

6

7 override fun onCreate() {

8 super.onCreate()

9 instance = this

10 }

11 }

lateinitis also indispensable when working with a dependency injector such as Dagger, and very useful for tests too.

Values from a map

Another way to delegate the values of a property is to get them from a map, using the name of the property as the key of the map. This delegate lets us do really powerful things, because we can easily create an instance of an object from a dynamic map.

If we are using immutable properties, the map can be immutable too. For mutable properties, the class will require aMutableMapas constructor parameter instead.

Imagine a configuration class we load from a Json, and assign those key and values to a map. We could just create an instance of a class by passing this map to the constructor:

16 Application Singleton and Delegated Properties 76

1 class Configuration(map: Map<String, Any?>) { 2 val width: Int by map

3 val height: Int by map 4 val dp: Int by map

5 val deviceName: String by map

6 }

As a reference, here it is how we could create the necessary map for this class:

1 val conf = Configuration(mapOf(

2 "width" to 1080, 3 "height" to 720, 4 "dp" to 240,

5 "deviceName" to "mydevice"

6 ))

In document Kotlin for Android Developers (Page 81-85)

Related documents