I have a love and hate relationship with Android. It’s fun and intuitive when it works, and it’s broken and cumbersome when it doesn’t. For example, I like the fact that simple activity can be programmed on one single file with no additional threads whatsoever, but this is not always good - UI thread hangs and ignored UI operations I have encountered are too many to count.

In my previous company, I had the opportunity to do whatever I like with Android, with all root permissions given. Some exotic goals of the software we were developing led me to process audio files with NDK, run a AOSP binary(!) inside NDK, process video frames in real-time with OpenCV etc. While working on these tasks, I’ve come across far more hurdles than I expected : broken NDK, device peculiarities, wrong & out-dated documentations etc. However, I can say with confidence that the worst thing about Android Development is the State Machines.

Numerous State Machines can be found in Android, most commonly seen one is MediaPlayer. Bluetooth & Bluetooth LE(Low Energy) connection system can be also described as State Machines. WifiManager has a State Machine inside it, and also the Camera API. These State Machines are so complicated that bare-bones description style of Android Developers just don’t cut - They often require a huge diagram with exceedingly many bullet-points below. Just reading these documents is daunting, but addition to that, you have to follow a badly described tutorial just to get a feel for it.

And what’s even worse - this is important - is that there are many undocumented nuisances that you WILL discover while testing it. Most of them are not intuition-friendly at all that they can be described as a Android bug and a workaround fix. And some of them might even be Android version or device specific - check the code of JavaCameraView in OpenCV to get a feel of it. In this code, there are more than 40 lines of code for opening a camera in all versions of Android & special devices, while in “theory” it should be possible using one line of code!

Another thing that is bad about these APIs is that most of them are asynchronous operations internally, but don’t seem like they do. MediaPlayer has a prepare method that looks like it returns right away, but it takes enough time that there is a method called prepareAsync which runs asynchronously and does return right away. And this is one of the clear cases. Some operations are really jumbled up(Bluetooth LE & Camera API are good examples) that given callbacks don’t really cut it - you have to manually set a time delay after certain operations, just to be safer that these operations are actually finished before moving on.

And lack of information these machines give out is stunning - in MediaPlayer, it is not even possible to know the state of machine from outside. And in WifiManager, it is not possible to know the result of connection attempt to a hotspot reliably. You have to periodically check the connection manually to find out if connection has succeeded. Also, there is no way you can say with confidence the reason connection has failed. In summary, these machines are too complicated & hard to debug, that getting anything done with them is a miracle.

Why is it like this? I suspect imperfect design - these APIs abstract away too many stuff that they are too leaky. If these APIs always do what they promise to do, I’m sure programming with them would be a lot easier and bug-free. And the world would be a better place.