Reducing noise in your database operations with Kotlin on Android
Kotlin has the capability to be the Pied Piper for your creativity. For me personally, Extensions and Higher Order Functions are the features that’s made programming in Kotlin delightful. It’s made me think about problems differently.
Extensions allows us to extend a class, without the overhead of initializing constructors, or implementing methods. It keeps us focused on building custom function(s) on top of the class of our choice, altogether eliminating the need for Utility classes.
For e.g., Suppose we have a variable where names of our users are stored as comma separated values of first and last names. How can we use Extensions so that String variable(s) will be able to fetch our users?
getUser() is the Extension function. The function name’s prefix tells us that we’re extending the String object allowing us to use the String’s split method inside our function body. Additionally, all String objects are allowed to call this method.
Higher Order Functions allows us to write a function that takes a function as a parameter. This makes writing *insert logic here* easy, especially useful when defining a repetitive pattern which used to be cumbersome (👋 Interfaces!).
For e.g., An Employee is to be evaluated to get a promotion. The employee will be evaluated by the HR department and his/her manager. Evaluators will have their own evaluation scores and criteria with a common threshold to determine if the employee is promoted or not.
isPromotableEmployee() is not bothered with the scoring implementation since it has delegated the responsibility to evaluate. However it is focused on comparing the evaluation score with a threshold allowing the function to nominate an employee as promotable.
We can further improve this by introducing Extensions; Extension Functions and Function Literals with Receivers. Functions Literals with Receivers are the same as Extension Functions with a key distinction on their level of abstraction. An Extension Function requires you to have a concrete definition of the function, while the latter lets you define a Higher Order function for the class you’re building upon.
The code feels fluid now. You can clearly see evaluators deciding whether employee is promotable by scoring them across different criteria.
Consequently higher order functions lets you write code avoiding any inherent dependency, i.e., inversion of control.
Getting to the meat of our discussion; the Database API on Android is verbose especially the Cursor. If you think about it we are essentially doing the same thing while querying for data, with minor differences.
Each database transaction follows these steps:
- Initialize your database instance,
- Write your database query,
- Fetch the corresponding Cursor,
- Iterate over Cursor; while checking the size of the Cursor,
- Mapping information from the Cursor onto an Object,
- Closing the Cursor, and
- Closing the database.
Only steps 2 and 5 will have varying implementations throughout the application. The big question now is can we write a general purpose, reusable function with Kotlin to solve this problem?
Let’s see what Kotlin’s standard library has to offer in use, which is an extension function for the Closable interface. use takes a higher order function as a parameter to *insert logic* while ensuring that the Closable object closes and the method returns our desired result.
Coincidentally both the SQLiteDatabase and Cursor are Closable implementations. With use our database queries could look like this:
We don’t have to worry about closing neither the Cursor nor the Database; use does that for us. In contrast, there’s this weird it in our code now. This it refers to the parameter inside our Higher Order Function. When we first use the database, it refers to the database; when we use the cursor, it refers to the cursor. However why use it when we can add in receivers?
You really start to appreciate the impact receivers have on code fluidity. Gone are the its; method access is now frictionless.
Our focus now is to create an abstract implementation of what we just did. Let’s start with step 5; Mapping information from the Cursor onto an Object. You would expect to either have an Object or a List of Objects returned to you.
The mapping logic will be a Higher Order Function here, leaving only the iteration logic for the Cursor to be defined.
The function is inlined to ease the impact of memory allocations resulting from the use of Higher Order Functions.
Moving onto step 2; Write your database query, which is a fairly easy task.
This implementation is complementary to step 5; it gives you your Object or Objects.
Finally, our database calls are filtered from all the noise. Altogether we have a focused and fluid syntax now.
This was just a small demonstration of how you can leverage Kotlin to enrich your development experience. It’s made me rekindle my love for Android and much more.
Get out there and Kotlin all things 😊