Kotlin KTX -set of extension for Android app dev

Kotlin_KTX

KOTLIN – KTX

Kotlin KTX is nothing but a  set of extensions designed to make writing Kotlin code for Android more concise, idiomatic, and pleasant. Android KTX provides a nice API layer on top of both Android framework and Support Library to make writing your Kotlin code more natural.

Currently in preview, Android KTX provides an API layer on top of the Android framework and Support Library — the former is available now on GitHub. Google promises to make the other parts of Android KTX that cover the Android Support Library available in upcoming Support Library releases.

To start using Android KTX in your Android Kotlin projects, add the following to your app module’s build.gradle file:

Top 10 free Android libraries for app development in android studio

We will start with Animation class:

Animator functions

There’s a collection of extensions related to animations within the library, let’s take a quick look at what we have available in the current release!

Animation listener

To begin with, in KTX we can set an animation listener on an animator instance like this:

animator.addListener { handleAnimation(it) }

This allows us to receive the callbacks for an animation event. We can even add function for specific callbacks of the listener, you’ll only need to pass functions for the callbacks that you want to receive data for:

animator.addListener(
        
onEnd = {}, 
       
onStart = {}, 
        
onCancel = {}, 
        
onRepeat = {}

)

This itself is a massive reduction in the code for listener callbacks that we may not need and use.

Individual animation event listeners

We have the ability to listen for individual events in android, with KTX adding a pause listener can be done in the same way that the addListener() function:

animator.addPauseListener { handleAnimation(it) }

// or 
animator.addPauseListener(

        onPause = {},

        onResume = {}
)

Again, only requiring to pass in the functions that we require to be used for the callbacks.

We can also listen for individual animation events in a single line of code:

animator.doOnPause { handleAnimation(it) }

animator.doOnCancel { handleAnimation(it) }

animator.doOnEnd { handleAnimation(it) }

animator.doOnRepeat { handleAnimation(it) }

animator.doOnStart { handleAnimation(it) }

animator.doOnResume { handleAnimation(it) }

By comparing the same code we do in Java for animations in your Android projects, you’ll notice how much less code (and how much easier to read) this is. In each of these calls above, it represents the Animator instance that is in use.

Time operations

KTX also offers a collection of operations related to Time.

We can now access the DayOfWeek, Month and Year instances as an Int value with a simple call:

DayOfWeek.FRIDAY.asInt()

Month.APRIL.asInt()

Year.now().asInt()

The Duration class also has a bunch of functions available:

// Retrieve values from destructuring
val (seconds, nanoseconds) = Duration.ofSeconds(1)

// Perform multiplication
val result = Duration.ofSeconds(1) * 2

// Perform division
val result = Duration.ofSeconds(2) / 2

// Perform negation
val result = -Duration.ofSeconds(2)

The InstantLocalDataLocalDateTimeLocalTime properties can also be accessed with these functions:

// Retrieve values in seconds
val (seconds, nanoseconds) = Instant.now()

// Retrieve year, month, day values
val (year, month, day) = LocalDate.now()

// Retrieve localDate, localTime values
val (localDate, localTime) = LocalDateTime.now()

// Retrieve hour, minute, second, nanosecond values
val (hour, minute, second, nanosecond) = LocalTime.now()

Accessing properties of the MonthDayOffsetDateTime and OffsetTime classes can easily be done via these  calls:

// Retrieve month day values 
val (month, day) = MonthDay.now()

// Retrieve timezone values 
val (localDataTime, ZoneOffset) = OffsetDateTime.now()

// Retrieve offset time values 
val (localTime, ZoneOffset) = OffsetTime.now()

These following functions are really helpful additions for the developer, these allow us to easily take an Int value and retrieve the corresponding representation for the given function call:

someIntValue.asDayOfWeek() // return DayOfWeek instance


someIntValue.asMonth() // returns Month instance


someIntValue.asYear() // returns Year instance


someIntValue.days() // returns Period instance


someIntValue.hours() // returns Duration instance


someIntValue.millis() // returns Duration instance


someIntValue.minutes() // returns Duration instance


someIntValue.months() // returns Period instance


someIntValue.nanos() // returns Duration instance


someIntValue.seconds() // returns Duration instance


someIntValue.years() // returns Period instance

The same goes for a Long instance also, using these functions the following representations can be retrieved:

someLongValue.asEpochMillis() // returns Instant instance


someLongValue.asEpochSeconds() // returns Instant instance


someLongValue.hours() // returns Duration instance


someLongValue.millis() // returns Duration instance


someLongValue.minutes() // returns Duration instance


someLongValue.nanos() // returns Duration instance


someLongValue.seconds() // returns Duration instance


Handler

Most used are the below methods to update or call UI methods using handler and they are so short to call,thank God.

handler.postAtTime(uptimeMillis = 200L) {
    // some action
}


handler.postDelayed(delayInMillis = 200L) {
    // some action
}

 Bundle class is short and nice:

val bundle = bundleOf("first_key" to 1, "second_key" to 2)


val bundle = persistableBundleOf("first_key" to 3, "second_key" to 4)

Utils

Within the Util package there are a collection of functions related to files, arrays and other general data types.

To begin with, if you’re working with AtomicFiles you’ll be able to make use of the following functions:

val fileBytes = atomicFile.readBytes()


val text = atomicFile.readText(charset = Charset.defaultCharset())
atomicFile.tryWrite {
    // some write operations
}


atomicFile.writeBytes(byteArrayOf())


atomicFile.writeText("some string", charset = Charset.defaultCharset())


For the LongSparseArraySparseArraySparseBooleanArraySparseIntArraySparseLongArray types we have all of the following functions available:(My Favorite)

array.contains(someKey)


array.containsKey(someKey)


array.containsValue(someValue)


array.forEach { key, value -> doSomething(key, value) }


array.getOrDefault(key = keyValue, defaultValue = defaultValue)


array.getOrElse(key = keyValue, defaultValue = defaultValue)


array.isEmpty()


array.isNotEmpty()


val keyIterator = array.keyIterator()


val valueIterator = array.valueIterator()


array.plus(anotherArray)


array.putAll(anotherArray)


array.remove(key = keyValue, value = value)


array.set(key = keyValue, value = value)


array.size

Working with the Pair class now becomes a little easier:

val pair = android.util.Pair("dsfn", "sdihfg")



// Retrieve values from destructuring
val (key, value) = pair


// Convert an Android framework pair to the kotlin Pair
val kotlinPair = pair.toKotlinPair()


We can also convert a Kotlin Pair directly to an Android Pair:

val pair = Pair("abcd", "efgh")



val androidPair = pair.toAndroidPair()


SQLite

For SQLite there is a single extension function available at this time. Even so, it’s a pretty handy addition that allows us to perform a transaction using the given SQL statement.How Sweet

sqLiteDatabaseInstance.transaction { "some SQL statement" }


Resources

When it comes to resources in our android applications, there have been a collection of functions added for easing the process of working with the TypedArray class.

val boolean = typedArray.getBooleanOrThrow(0)


val int = typedArray.getColorOrThrow(0)


val colorStateList = typedArray.getColorStateListOrThrow(0)


val float = typedArray.getDimensionOrThrow(0)


val int = typedArray.getDimensionPixelOffsetOrThrow(0)


val int = typedArray.getDimensionPixelSizeOrThrow(0)


val drawable = typedArray.getDrawableOrThrow(0)


val float = typedArray.getFloatOrThrow(0)


val typeface = typedArray.getFontOrThrow(0)


val int = typedArray.getIntOrThrow(0)


val int = typedArray.getIntegerOrThrow(0)


val string = typedArray.getStringOrThrow(0)


val charSequenceArray = typedArray.getTextArrayOrThrow(0)


val charSequence = typedArray.getTextOrThrow(0)


Text

Most of the applications we work in are going to use text somewhere throughout the project and thankfully, KTX provides some extension functions when it comes to these parts. For text we essentially have some functions available for the SpannableStringBuilder class.

For example, after instantiating a Builder instance we can use the build methods to append some bold text:

val builder = SpannableStringBuilder(urlString)        
    .bold { append("hi there") }


// or even some bold / italic / underlined text if you want!

val builder = SpannableStringBuilder(urlString)        
    .bold { italic { underline { append("hi there") } } }

There are also build functions to set the background color or wrap the text that you’re appending in spans:

.backgroundColor(color = R.color.black) { 
    // builder action
} 

.inSpans(spans = someSpans) { 
    // builder action
}


For buildSpannedString extension function that allows us to build a string and use the provided builder actions to provide our styling:

textView.text = buildSpannedString { bold { append("hitherejoe") } }


Transitions

when it comes to the Transition class we have a bunch of extension functions available for use. Just like the animation listeners, we can now easily listen for changes in our Transition by using the addListener() function call.

transition.addListener { doSomethingWithTransition(it) }



transition.addListener(onEnd = {}, onStart = {}, onCancel = {}, 
        onResume = {}, onPause = {})

Also we have individual functions created for receiving callback  :

transition.doOnCancel {  }


transition.doOnEnd {  }


transition.doOnPause {  }


transition.doOnResume {  }


transition.doOnStart {  }


Views

For the View class we have below functions. Setting callbacks for layout events is very clean:

view.doOnLayout {  }


view.doOnNextLayout {  }


view.doOnPreDraw {  }


Updating the padding for a view is now a lot cleaner and easier to do so, there are several functions available for it:

view.setPadding(16)


view.updatePadding(left = 16, right = 16, top = 16, bottom = 16)


view.updatePaddingRelative(
        start = 16, end = 16, top = 16, bottom = 16)

For converting a View instance to a Bitmap, you just need the single line of code!

val bitmap = view.toBitmap(config = bitmapConfig)


Margins

We can now set the margins for our layout (params) instances with the following functions:

params.setMargins(20)


params.updateMargins(left =20, right =20, top =20, bottom =20)


params.updateMarginsRelative(
        start =20, end =20, top =20, bottom =20)


ViewGroup

There are some handy ViewGroup related functions that you’ll likely be using in your projects! For example, checking a if a viewgroup contains a view:

val doesContain = viewGroup.contains(view)


Looping through the children of a viewgroup

viewGroup.forEach { doSomethingWithChild(it) }


viewGroup.forEachIndexed { index, view -> 
    doSomethingWithChild(index, view) }


Accessing the child at a desired position in Kotlin way:

val view = viewGroup[0]


We can perform other various viewgroup related operations:

viewGroup.isEmpty()


viewGroup.isNotEmpty()


viewGroup.size


// Remove a view from the given viewgroup
viewGroup -= view


// Add a view to the given viewgroup
viewGroup += view


With these functions also we have major changes also for Graphics class.

Master Gradle dependency management with Kotlin + buildSrc for Android

Do let me know how you feel about this post in comment section. I hope we will see more exciting changes in Kotlin – KTXwhich will make the life of Android developer easy and interesting.

I hope you enjoy this post related to Kotlin – KTX and started with the beautiful language Kotlin.