Jose Álvarez
Posted on March 16, 2021
This post is about a recopilation of most used extension functions on kotlin for Android Framework.
Event
This utility class is recomended by Google Team to use events in LiveData
, is designed for help us to process events, that check if its used or not. Because when a configuration change occurs in the device, the events we are observing may occur when they actually do not.
open class Event<out T>(private val content: T) {
private var hasBeenHandled = false
fun getContentIfNotHandled(): T? {
return if (hasBeenHandled) {
null
} else {
hasBeenHandled = true
content
}
}
}
Now that you know what is used for, you're going to understand the following function.
1. ObserveEvent:
Its very interesting function for the Event
class, in particular for LiveData<Event<T>>
, whose function is facilitate our work when observing events.
inline fun <T> LiveData<Event<T>>.observeEvent(
owner: LifecycleOwner, crossinline onEventUnhandledContent: (T) -> Unit) {
observe(owner, Observer { it.getContentIfNotHandled()?.let(onEventUnhandledContent) })
}
The use is similar when we observe a LiveData
from activity or fragment, only instead of call observe
method, we must call observeEvent
method, passing a lambda as argument.
// Para un LiveData<Event<Int>> it será Int.
viewModel.eventLiveData.observeEvent(this) { doAction(it)}
Fragment
SetToolbarButtonAndTitle
Without a doubt this function should be the most used, because to work with fragment allow us establish the navigation button and the toolbar title easily.
fun Fragment.setToolbarButtonAndTitle(string: String){
(requireActivity() as AppCompatActivity).supportActionBar?.run {
setDisplayHomeAsUpEnabled(true)
title = string
}
}
Usage:
fun setupViews() {
setToolbarButtonAndTitle(getString(R.string.fragment_title))
}
Arguments
Obtaining fragment arguments is a bit ugly process, so i bring us a couple of extension fucntions, that makes it easy for us to obtain arguments in fragment.
fun Fragment.extraBoolean(extraId: String, default: Boolean = false) = lazy { arguments?.getBoolean(extraId, default) ?: default }
fun Fragment.extraInt(extraId: String, default: Int = 0) = lazy { arguments?.getInt(extraId, default) ?: default}
fun Fragment.extraString(extraId: String, default: String = "") = lazy { arguments?.getString(extraId) ?: default }
LiveData
GetValue
One of the biggest inconveniences of using LiveData
is obtaining its value, because can return null and we ever check it with Elvis operator.
Now with this couple of functions we haven't worry about of that, only when we want obtain LiveData
value we must call her getValue
method, passing a default value by params
fun LiveData<Int>.getValue(defaultValue:Int) : Int = value ?: defaultValue
fun LiveData<String>.getValue(defaultValue:String) : String = value ?: defaultValue
fun LiveData<Long>.getValue(defaultValue:Long) : Long = value ?: defaultValue
fun LiveData<Boolean>.getValue(defaultValue:Boolean) : Boolean = value ?: defaultValue
Clearly this is only a example, you can create for more types
Spinner
SetOnItemSelectedListener:
This function is quite useful to set the listener of an adapter and not having to implement all the methods of the AdapterView.OnItemSelectedListener
interface, but by using it directly we pass the function to be performed when a Spinner item is selected.
fun Spinner.setOnItemSelectedListener( onNothingSelectedAction: (parent: AdapterView<*>?) -> Unit = {},
onItemSelectedAction: (parent: AdapterView<*>?, view: View?, position: Int, id: Long) -> Unit) {
onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) { onNothingSelectedAction(parent)}
override fun onItemSelected(parent: AdapterView<*>?, view: View?,
position: Int, id: Long) {
onItemSelectedAction(parent, view, position, id)
}
}
}
Usage:
spinner.setOnItemSelectedListener { _, _, _, _ -> doAction() }
Toast
1. showToast:
This function we save a lot of time to show a toat, making code more readable
fun Context.toast(message: String, duration: Int = Toast.LENGTH_SHORT) {
Toast.makeText(this, message, duration).show()
}
Usage:
toast(getString(R.string.message)
Note: We should keep in mind, that to call this function from fragment we have to call before getContex
method.
context.toast(getString(R.string.message))
RecyclerView
1. setOnSwipeListener:
This function allows us to easily set an action for when an element of the RecyclerView
is dragged sideways to the left or right (default). Making the code more readable.
fun RecyclerView.setOnSwipeListener( swipeDirs: Int = ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT,
onSwipe: (viewHolder: RecyclerView.ViewHolder, direction: Int) -> Unit = { _ , _ -> }) {
val itemTouchHelper = ItemTouchHelper(
object : ItemTouchHelper.SimpleCallback(0, swipeDirs) {
override fun onMove(recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder): Boolean = false
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
onSwipe(viewHolder, direction)
}
})
itemTouchHelper.attachToRecyclerView(this)
}
Usage:
recyclerView.setOnSwipeListener { viewHolder, _ -> doAction(viewHolder.currentList[viewHolder.adapterPosition]) }
Intent
requireParcelableExtra
To save us all the checks to obtain an intent, we can use this extension function that does all the checks for us, which receives the id of the extra to extract and will return an Any
object.
fun Intent.requireParcelableExtra(extraId:String):Any? {
if (!hasExtra(extraId)) throw RuntimeException("Intent is not valid, must have EXTRA_POKEMON")
return getParcelableExtra(extraId)
}
Usage:
if (result.resultCode == RESULT_OK && intentResult != null) {
intentResult.requireParcelableExtra(EXTRA_ID) as Int
}
TextView
strikeThrough
With this function we can strike out the TextView
text easily.
fun TextView.strikeThrough(strike: Boolean) {
paintFlags = if (strike) {
paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
} else {
paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
}
}
Usage:
binding.lblTaskSubject.strikeThrough(isCompleted)
View
GoneUnless
This extension function is very popular and very useful, that's why I think it deserves to be in this compilation. Besides, it is very useful to use it in layouts with dataBinding
.
fun View.goneUnless(condition: Boolean) {
visibility = if (condition) View.VISIBLE else View.GONE
}
Usage:
binding.emptyView.goneUnless(list.isEmpty)
HideKeyboard
It allows to hide the virtual keyboard simply invoking it, we must call it with a view that generally will be an EditText
.
fun View.hideKeyboard(): Boolean {
try {
val inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
return inputMethodManager.hideSoftInputFromWindow(windowToken, 0)
} catch (ignored: RuntimeException) { }
return false
}
Usage:
binding.edtName.hideKeyboard()
Posted on March 16, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 21, 2024