Contents
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 Instant, LocalData, LocalDateTime, LocalTime 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 MonthDay, OffsetDateTime 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 LongSparseArray, SparseArray, SparseBooleanArray, SparseIntArray, SparseLongArray 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.
Ravi Yadav is an Android developer whose passion is to develop Android applications and sharing his work. He loves to post the tutorials which he created while learning any new latest technology topic.He loves to share about the latest technology happenings and other tricks that will be helpful for readers of Askfortricks.
Feeling glad to receive your comment