Awesome Kotlin Extension Functions for Android

Awesome Kotlin Extension Functions for Android

Some handy Kotlin Extension functions to add syntactic sugar and clean up code in your Android project.

·

4 min read

Kotlin Extension functions are an awesome way to extract and clean up code in your Android project. No one likes typing out Toast.makeText(context,"My message",Toast.LENGTH_SHORT).show(), takes too much time for something so simple. This along with Android studio giving random auto complete suggestions makes it frustrating.
Incomes Kotlin Extension functions.

Extension functions

Toasts

internal fun AppCompatActivity.showToast(message: String, length: Int = Toast.LENGTH_SHORT) = Toast.makeText(this, message, length).show()
internal fun Fragment.showToast(message: String, length: Int = Toast.LENGTH_SHORT) = Toast.makeText(context, message, length).show()
internal fun Context.showToast(message: String, length: Int = Toast.LENGTH_SHORT) = Toast.makeText(this, message, length).show()

You could just use the context version of the function, but since it is Context and not Context? in fragments you would be calling the requireContext() function than the getContext() property. So, I just have all three of these and use them in appropriate cases.

For SnackBars

internal fun View.shortSnackBar(message: String, action: (Snackbar.() -> Unit)? = null) {
  val snackbar = Snackbar.make(this, message, Snackbar.LENGTH_SHORT)
  action?.let { snackbar.it() }
  snackbar.show()
}

internal fun View.longSnackBar(message: String, action: (Snackbar.() -> Unit)? = null) {
  val snackbar = Snackbar.make(this, message, Snackbar.LENGTH_LONG)
  action?.let { snackbar.it() }
  snackbar.show()
}

internal fun View.indefiniteSnackBar(message: String, action: (Snackbar.() -> Unit)? = null) {
  val snackbar = Snackbar.make(this, message, Snackbar.LENGTH_INDEFINITE)
  action?.let { snackbar.it() }
  snackbar.show()
}

internal fun Snackbar.action(message: String, action: (View) -> Unit) {
  this.setAction(message, action)
}

This extension function uses the power of Default arguments and lambdas.
So, We can just show the message without any action or pass the action through a lambda like

myFab.shortSnackBar("My Message"){
  action("Undo"){
    //Do action task here
  }
}

You can also eliminate the need for having three functions for each duration by having another parameter like so,

internal fun View.showSnackBar(message: String, length: Int = Snackbar.LENGTH_SHORT, action: (Snackbar.() -> Unit)? = null) {
    val snackbar = Snackbar.make(this, message, length)
    action?.let { snackbar.it() }
    snackbar.show()
}

But do be sure which View reference you're calling this with.

Starting Activities

internal inline fun <reified T : Activity> Activity.launch(block: Intent.() -> Unit = {}) {
    val intent = Intent(this, T::class.java)
    intent.apply(block)
    startActivity(intent)
}

internal inline fun <reified T : Activity> Activity.launchAndFinish(block: Intent.() -> Unit = {}) {
    val intent = Intent(this, T::class.java)
    intent.apply(block)
    startActivity(intent)
    finish()
}

internal inline fun <reified T : Activity> Activity.launchAndFinishAffinity(block: Intent.() -> Unit = {}) {
    val intent = Intent(this, T::class.java)
    intent.apply(block)
    startActivity(intent)
    finishAffinity()
}

These functions are useful to start Activities without having to handle creating intents and writing finish all the time.
Just call these like so,

launchAndFinish<DestinationActivity>()

//or with intent options

launchAndFinish<DestinationActivity>(){
  putString("myKey", myString)
}

The other way to do this is to have a static function in the destination class that handles all the intent options and extras depending on it's use. This is a good approach as well where the extra's are strictly made compulsory and properly defined by the destination class.
For example,

class DestinationActivity : AppCompatActivity(){

  //....

  companion object{
    private val EXTRA_KEY = "myKey"

        fun newIntent(context: Context, myString: String): Intent {
            val intent = Intent(context, DestinationActivity::class.java)
            intent.putString(EXTRA_KEY, myString)
            return intent
        }
  }
}

This is called as so,

val intent = DestinationActivity.newIntent(this, myString)
startActivity(intent)

Starting Fragments

Here's where it gets blurry, if you're writing your transactions by yourself, then extension functions come in use to get rid of some code duplication. If not and you're using Jetpack navigation with SafeArgs, then use the ktx dependency for pre-included extension functions.

Live data

fun <T> AppCompatActivity.observe(liveData: LiveData<T>, action: (t: T) -> Unit) {
    liveData.observe(this) { t -> 
      action(t) 
    }
}
fun <T> Fragment.observe(liveData: LiveData<T>, action: (t: T) -> Unit) {
    liveData.observe(viewLifecycleOwner) { t -> 
      action(t) 
    }
}

Although this isn't useful for syntactic purposes, it can prevent you from mistakenly using this as lifecycle owner in a fragment.

Form/String Validations

internal fun String.isValidPassword(): Boolean = (this.length >= 8 && !this.isBlank())
internal fun String.isEmailValid(): Boolean = (Patterns.EMAIL_ADDRESS.matcher(this).matches() && !this.isBlank())

Depending upon your use case, you can make string validation like these to perform validation.
Also you could check out this handy library afollestad/vvalidator for easy form validation that uses Kotlin DSL syntax.

Other Utility functions

internal fun Date.getFriendlyString(): String {
    val currentTime = Date()
    val timeInAgo = DateUtils.getRelativeTimeSpanString(this.time, currentTime.time, DateUtils.MINUTE_IN_MILLIS)
    return timeInAgo.toString()
}
internal fun View.toggleGone() {
     this.isGone = !this.isGone
}

Feel free to comment other useful one's that you find :)
That’s All!
Thank you for reading.
Check me out on GitHub.