I just finished working on a personal side-project to improve my Android development skills. I’ve had the opportunity to work on a few Android apps at work at Canadian Tire on the Innovations team but they were Cordova-based or otherwise using HTML for the user interface and I wanted to experience full native Android development. What has come out of my efforts is far from perfect but I have a much better grasp of the challenges and opportunities in native Android development.
The purpose of app I built is to remind me to register the vehicles of people who stay past midnight at my apartment so they do not receive parking tickets. The way the app achieves its purpose is at 11:00 pm everyday, it queries my router for a list of MAC addresses connected to it, then compares that list to a whitelist of MAC addresses of devices that are known not to belong to visitors, and then raises an Android notification if a MAC address not in that whitelist is detected. Seeing that I have that notification, I would then know I need to potentially register somebody’s vehicle with my apartment building’s guest parking registration system.
To get the list of connected devices, the app takes advantage of three JSON-RPC APIs that my router running OpenWRT exposes to get the ARP table containing a sequence of tuples of MAC address and IP address, a list of active connections containing source IP addresses which takes advantage of the persistent connections mobile phones make to the Internet for receiving push notifications, and a mapping of MAC address to hostname so I have a hint as to what device is tied to that MAC address. The MAC address whitelist is built using a user interface that queries the router for connected devices and then the user categorizes those devices into home devices and visitor devices.
I’d heard about Kotlin a few times when I decided to start working on this app and was curious to see how I would find it compared to Java. I thought I’d go through here and share what I enjoyed from using it and what I didn’t like.
Kotlin is less verbose than Java and enables me to express more constraints. Things like specifying that a variable can’t be null, that it should be final (without needing an additional keyword), that it will be late-initialized are useful constructs to have available.
when statements which are like
switch statements but better, lead to more readable code and can even help the compiler in some cases raise warnings which would not be possible using equivalent
if statements. Kotlin’s collections in its standard library are also reasonably well-designed in that they are immutable by default and have typical functional collection-oriented methods available (e.g.,
filter). Java inter-op is also relatively straightforward. Kotlin is very easy to learn if you know Java.
One thing I don’t like about Kotlin is it’s aversion to return statements in lambdas. I understand that this was done as lambdas are not implemented as discrete methods after compilation so the language authors did not want the compiler to think that a return inside a lambda block should exit the outer function, but I don’t think it would be expensive to re-write that part of the AST during compilation so that the destination of the return instruction could be properly understood by a future compilation step. I found writing a JUnit parameterized test and using a number of Mockito methods to be cumbersome with Kotlin due to breakdowns in how types are inferred. Static analysis tooling is also less advanced than what’s available for Java once you go beyond the constructs Kotlin provides so certain other types of errors are harder to automatically detect. That being said, I would argue the better null-safety Kotlin provides outweighs that loss.
Overall, I enjoyed using Kotlin and I would certainly consider using it again.
I find Android to be an interesting if also frustrating platform to code for. Part of that is likely a lack of familiarity on my part. Whereas I’ve been doing web development for around a decade, I’ve done less than a year’s worth of Android development. The state management and model for UI development is obviously very different which takes getting used to.
Most of my frustrations come down to what I would consider the default, intuitive way of writing a piece of code is very likely to cause an issue. Jeff Atwood has a good blog post on the pit of success versus the pit of despair in the context of C++ (https://blog.codinghorror.com/falling-into-the-pit-of-success/) and I think Android falls into the pit of despair side of the API design spectrum. As an example, if you to perform a background operation like an HTTP request, the developer documentation encourages you to use an
AsyncTask which interacts poorly with the end of a fragment/activity lifecycle with no obvious mitigation. Another example is that an item in a list view has three different boolean states associated with it: selected, checked, and activated. It’s not immediately obvious which one or ones you need to care about in a given context. Another aspect that I don’t like is that the typical way to implement something in the UI is to inherit from a UI object or objects and override one or more methods instead of composing them inside of an interface implementation. The inheritance model tends to break down when different methods in an ancestor class interact with each other in unintuitive ways. I’ve also found the Google support libraries sometimes have rather obvious gaps. As another example, the
SwipeRefreshLayout does not support swipe to refresh on a
TextView configured to be used when a
ListView is empty. An empty list is what I would consider an obvious state to support swipe to refresh. There’s a lot that I could complain about but I think that’s sufficient for this post.
Luckily there are a number of very helpful open source libraries out there to help with Android development. Here are some I would recommend considering:
- Dagger is a dependency injection framework for Android. I find using a dependency injection framework makes it easier to design objects that can be unit tested
- Timber is a logging framework built on top of the built-in Android one with a better API and is also more extensible
- EventBus is an Android optimized event bus which simplifies communication between different parts of an Android app
Another thing I’m hopeful about is it looks like there are a number of new libraries and frameworks becoming available for UI development on Android. Google’s databinding library was in beta when I wrote most of the UI of my app so I didn’t use it in this app but it looks like it’s now out of beta so I’d be curious to know if it alleviates some of the pain. React Native is another framework that I’m curious about, especially combining it with Redux. Anvil is another approach that enables data-binding by moving the UI from XML to code. I think this will be an interesting space to watch.