Extension function in complete details
Complete details with questions raised for the Extension function
Explanation
In Android, an extension function allows you to add new functionalities to existing classes without modifying their source code. It’s a powerful feature of Kotlin, the primary language used for Android development, that enables you to extend any class, including third-party libraries or Android framework classes, with your custom methods.
To define an extension function in Kotlin, you use the following syntax:
fun ReceiverType.functionName(parameter(s): ParameterType): ReturnType {
// Function body
}ReceiverType: The class you want to extend.functionName: The name of the new function you want to add.parameter(s): The parameters that the new function takes, if any.ReturnType: The return type of the new function.
Now let’s explore some scenarios where you can use extension functions in Android with coding examples:
Adding Utility Functions:
Suppose you want to add a utility function to the String class that capitalizes the first letter of a string.
// Extension function to capitalize the first letter of a string
fun String.capitalizeFirstLetter(): String {
return this.replaceFirstChar { it.uppercase() }
}Usage:
val myString = "hello world"
val capitalizedString = myString.capitalizeFirstLetter()
println(capitalizedString) // Output: "Hello world"Simplifying Null Checks:
You can create an extension function to simplify null checks on View objects by providing a safer way to set click listeners.
// Extension function to set click listener safely
fun View.setSafeOnClickListener(onClickAction: () -> Unit) {
setOnClickListener {
it?.let {
onClickAction()
}
}
}Usage:
// Suppose you have a button with the ID "myButton" in your layout
val myButton = findViewById<Button>(R.id.myButton)
// Now you can set the click listener safely using the extension function
myButton.setSafeOnClickListener {
// Handle button click here
}Customizing Third-Party Classes:
You can add additional functionality to third-party classes without modifying their source code. Let’s say you want to add a method to the Date class that formats the date as "dd-MM-yyyy."
// Extension function to format Date as "dd-MM-yyyy"
fun Date.formatAsDDMMYYYY(): String {
val dateFormat = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault())
return dateFormat.format(this)
}Usage:
val currentDate = Date()
val formattedDate = currentDate.formatAsDDMMYYYY()
println(formattedDate) // Output: "03-07-2023"Customizing Android Framework Classes:
Example: Adding a method to the EditText class to clear its text and hide the soft keyboard.
fun EditText.clearAndHideKeyboard() {
setText("")
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(windowToken, 0)
}Usage:
val myEditText = findViewById<EditText>(R.id.myEditText)
myEditText.clearAndHideKeyboard()Convenience Methods for Working with Colors:
Example: Adding a method to the Int class to convert an integer color value to a hexadecimal string.
fun Int.toHexColor(): String {
return String.format("#%06X", 0xFFFFFF and this)
}Usage:
val colorInt = 0xFF336699.toInt()
val hexColor = colorInt.toHexColor()
println(hexColor) // Output: "#336699"Handling SharedPreferences:
Example: Adding methods to the SharedPreferences class to easily read and write values.
fun SharedPreferences.putString(key: String, value: String) {
edit().putString(key, value).apply()
}
fun SharedPreferences.getString(key: String, defaultValue: String): String {
return getString(key, defaultValue) ?: defaultValue
}Usage:
val sharedPreferences = getSharedPreferences("my_prefs", Context.MODE_PRIVATE)
sharedPreferences.putString("username", "JohnDoe")
val username = sharedPreferences.getString("username", "")Transforming Collections:
Example: Adding a method to the List class to filter out null elements.
fun <T : Any> List<T?>.filterNonNull(): List<T> {
return filterNotNull()
}Usage:
val nullableList = listOf("A", null, "B", "C", null, "D")
val nonNullList = nullableList.filterNonNull()
println(nonNullList) // Output: ["A", "B", "C", "D"]View Related Functions:
Example: Adding an extension function to a View to show a simple toast message.
fun View.showToast(message: String, duration: Int = Toast.LENGTH_SHORT) {
Toast.makeText(context, message, duration).show()
}Usage:
val myButton = findViewById<Button>(R.id.myButton)
myButton.showToast("Button Clicked!")Manipulating Dates and Times:
Example: Adding an extension function to the Long class to convert milliseconds to a formatted time string.
fun Long.toFormattedTimeString(): String {
val sdf = SimpleDateFormat("HH:mm:ss", Locale.getDefault())
return sdf.format(Date(this))
}Usage:
val currentTimeMillis = System.currentTimeMillis()
val formattedTime = currentTimeMillis.toFormattedTimeString()
println(formattedTime) // Output: "12:34:56"Handling Network Responses:
Example: Adding an extension function to the Response class to handle API responses and return the result or error.
inline fun <reified T> Response<
With RecylcerView
Suppose you have an Android application that uses a RecyclerView to display a list of items. You want to add a function that scrolls the RecyclerView to the top when called. Here's how you can achieve that using an extension function:
// Extension function to scroll RecyclerView to the top
fun RecyclerView.scrollToTop() {
this.scrollToPosition(0)
}Usage:
val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
// ... setup the RecyclerView
// Now, you can call the scrollToTop() function on the RecyclerView
recyclerView.scrollToTop()In this example, we define an extension function named scrollToTop() on the RecyclerView class. This function scrolls the RecyclerView to the top by calling the scrollToPosition(0) method. By using extension functions, we can add this behavior to the RecyclerView class without modifying its original source code.
Code Reusability:
Extension functions promote code reusability by allowing you to add common functionalities to existing classes. Instead of writing the same utility methods repeatedly, you can define them as extension functions and reuse them across your codebase.
Get Amit Dhiman’s stories in your inbox
Join Medium for free to get updates from this writer.
Example: Suppose you frequently need to check if a String is empty or blank. You can define an extension function to simplify this check:
// Extension function to check if a String is empty or blank
fun String?.isEmptyOrBlank(): Boolean {
return this == null || this.trim().isEmpty()
}Usage:
val text1: String? = null
println(text1.isEmptyOrBlank()) // Output: true
val text2: String? = ""
println(text2.isEmptyOrBlank()) // Output: true
val text3: String? = " "
println(text3.isEmptyOrBlank()) // Output: true
val text4: String? = "Hello"
println(text4.isEmptyOrBlank()) // Output: falseReadability and Expressiveness:
Extension functions enhance code readability by allowing you to write more natural and intuitive code. They enable you to express operations in a way that closely resembles natural language.
Example: Suppose you want to format a Date object as a readable string. With an extension function, you can achieve a more expressive and readable code:
// Extension function to format Date as a readable string
fun Date.formatReadable(): String {
val dateFormat = SimpleDateFormat("MMM dd, yyyy", Locale.getDefault())
return dateFormat.format(this)
}Usage:
val currentDate = Date()
val formattedDate = currentDate.formatReadable()
println(formattedDate) // Output: "Jul 03, 2023"Enhancing Third-Party Libraries:
Extension functions allow you to add functionalities to third-party libraries without modifying their original source code. This enables you to tailor the behavior of those libraries to better suit your needs.
Example: Suppose you are using a library that provides a custom ImageView class and you want to add a method to load an image from a URL using a library like Glide:
// Extension function to load an image from a URL using Glide
fun ImageView.loadFromUrl(url: String) {
Glide.with(context).load(url).into(this)
}Usage:
val imageView = findViewById<ImageView>(R.id.imageView)
imageView.loadFromUrl("https://example.com/image.jpg")Easy Integration with Existing Codebase:
Extension functions can seamlessly integrate with your existing codebase without requiring major modifications. You can introduce new functionalities without breaking existing code or introducing complex inheritance hierarchies.
Example: Suppose you have a legacy codebase where you need to work with an IntArray and you want to find the sum of its elements. You can define an extension function to calculate the sum easily:
// Extension function to calculate the sum of IntArray elements
fun IntArray.sum(): Int {
var total = 0
for (element in this) {
total += element
}
return total
}Usage:
val numbers = intArrayOf(1, 2, 3, 4, 5)
val sum = numbers.sum()
println(sum) // Output: 15Utility Functions:
Extension functions are often used to add utility functions that provide common functionalities across different classes or data types. For example, you can create extension functions for string manipulation, date formatting, type conversions, or mathematical operations.
Example: Adding a utility function to format a number as currency.
fun Double.formatAsCurrency(): String {
return NumberFormat.getCurrencyInstance().format(this)
}Customizing Framework or Third-Party Classes:
Extension functions allow you to add additional functionalities to framework or third-party classes without modifying their original code. This can be useful when you want to extend the behavior of existing classes to suit your specific needs.
Example: Adding a method to the TextView class to set the text color using a color resource ID.
fun TextView.setTextColorRes(@ColorRes colorResId: Int) {
val color = ContextCompat.getColor(context, colorResId)
setTextColor(color)
}Simplifying APIs:
Extension functions can be used to simplify complex or verbose APIs by providing more concise and readable syntax. This can improve the overall code readability and maintainability.
Example: Simplifying the process of adding multiple items to a MutableList.
fun <T> MutableList<T>.addAll(vararg elements: T) {
addAll(elements)
}View-related Operations:
Extension functions can be used to define common view-related operations or behaviors that can be reused across different views or layouts. This can help in reducing code duplication and promoting consistency in UI-related tasks.
Example: Adding a method to the View class to set visibility based on a boolean value.
fun View.setVisible(visible: Boolean) {
visibility = if (visible) View.VISIBLE else View.GONE
}Domain-Specific Operations:
Extension functions can be used to define domain-specific operations or behaviors that are specific to your application’s business logic or domain model.
Example: Adding methods to a List of custom Product objects to filter and sort based on specific criteria.
fun List<Product>.filterByCategory(category: String): List<Product> {
return filter { it.category == category }
}
fun List<Product>.sortByPrice(): List<Product> {
return sortedBy { it.price }
}
I found this article of medium is helpful https://medium.com/kayvan-kaseb/extension-function-in-kotlin-ef52e4319e81





