Android development revisited

06 September 2019
Over the last two months or so I have been getting back into Android programming, which is in contrast to the electronics projects that have tended to take up my spare time over the prior two years. As with anything that has not been looked at for years it was harder than I expected to get back into it, but it was a process that although frustrating was not particularly drawn out. Android programming is not something I would make a career of, but it was interesting to try it again.

A brief background

I first tried Android programming while still in New Zealand, but it was only around mid-2014 that I got further than experimentation and wrote functional apps. One of these apps was a proof-of-concept map tool that I think was supposed to be pitched at a zoo in Melbourne or Sydney by my brother — cannot remember which as as the Google Maps API it uses no longer works, most likely due to API key issues — but for reasons long-forgotten was abandoned. I can't remember if this is due to a change of jobs at the time, or whether the pitch simply never happened.

The last Android app I wrote was one that did real-time Fourier Transforms of images from the phone's camera, and according to time-stamps was written in the summer of 2015. After then I pretty much did not look at Android development again until this year, because I felt that I had already figure out everything I wanted to and since then had other priorities for my spare time. I eventually got back into Android programming as part of a project involving my brother and a few colleagues, although the circumstances in which I joined this project involved conflicts of which I am mostly unaware of the details of.

Android vs. iOS

Back in 2014 Windows Phone was still in the market and to be fair some good handsets did come out before Microsoft finally threw in the towel, but I had personally already written Microsoft's mobile offerings off by this stage. I had some distrust due to Microsoft's past monopolistic practices and their attempt at creating a unified desktop and mobile eco-system, but fundamentally for me personally they were simply too late to capitalise on any interest I had from my prior use of Windows Mobile. Apple had the premium market and Google had the mass-market, so the Windows Store looked like an also-ran thank sank without trace pretty quickly.

My usual analysis is that Apple had the premium market and Google had the mass-market but these days the high-end Android devices often have features that put the iPhone to shame. For me the biggest problem with iOS is that the development system is only available for MacOS, and I simply have no interest in buying Apple computers or phones. Although Google Play requirements have been tightened up, Google's attitude is that pretty much anything short of malicious tools and malware is allowed, whereas iPhone has been much more of a walled garden and publishing on Apple Store requires jumping through quite a lot of hoops.

The Android eco-system

Unlike Apple iOS and the now-dead Windows Phone systems that as far as I know came with polished IDE packages, the Android SDK started life as command-line tools based on how things were in the Java world. I dislike Java but the Android implementation, at least at the time, avoided some of the worst aspects of Java eco-systems. Unlike the other two Android was cross-platform, which for me was essential — iOS requires expensive Apple Macs, and I hated the interface of more recent versions of Visual Studio.

Stand-alone SDK use

When I first started doing Android programming the whole development eco-system was a little messy, requiring a bit of fiddling to get things working. Android Studio was still experimental at the time, only reaching beta status in mid-2014 with the “stable” v1.0 being released at the end of the year, so the SDK package was made for stand-alone use in its own right. One effect of this is that it included front-ends for setting things up — a screen-shot of the SDK component tool is shown below.

Android package selection

Spin forward to 2019 and it seems that these days the stand-alone SDK distribution is little more than packaging of the Android Studio back-end, and as a result no longer included the nice configuration tools of the past. I suspect that it is only really intended for use in making automated build servers rather than actual development, as in places it makes reference to Android Studio for configuration. Luckily I still had copies of the older SDK, which is capable of downloading all the latest components, but in the end I figured out the commands needed to install the components I intended to use:

mkdir AndroidSDK cd AndroidSDK unzip ~/Downloads/sdk-linux-*.zip export sdk_manager=${ANDROID_SDK}/tools/bin/sdkmanager ${sdk_manager} "build-tools;28.0.3" ${sdk_manager} "platform-tools" ${sdk_manager} "platforms;android-29" ${sdk_manager} "emulator" ${sdk_manager} "system-images;android-19;default;x86" ${sdk_manager} "system-images;android-28;google_apis;x86_64"

In the past Android projects used Apache Ant but before long it became apparent that it would be a world of pain as all the documentation out there assumes the use of Gradle as a build system, which for reasons covered later I was not find of using. I tried setting up an Android project by hand based but in the end I used Android Studio to create an empty project, which I then refactored to remove some of the excessively-deep directory structures.

SDK changes

Compared to what I remembered from 4-5 years ago the structure of Android projects is a little different, the most noticeable aspect being the renaming of drawable for graphics to mipmap, and the former being recycled for vector-based graphics. In isolation little changes like this are bearable, but five years' worth of such little changes means that I had to question the value of my previous Android experience. User-interface tool-kits have a reputation for lack of long-term consistency, but it seems Google has thrown away almost all sense of conservatism in the design of Android.

My previous development used API revision 19 (i.e. Android 4.4.2) whereas the current revision is 29, and over the last ten revision there seems to have been a lot of deprecation, whereas prior to API 19 changes were pretty much entirely additions. I think there was a lot of new stuff in API 19 which explains why for quite a long time it has been the oldest API that is widely supported. I disliked a lot of the interface changes between Android 4.4.2 and 5.0 so at time of writing still used a phone that was limited to API 19. API 20 (i.e. Android 5+) introduced a few extra things such as semi-transparent backgrounds, which although not critical from my perspective, are slightly annoying to do without.

What API to target?

I think API 19 is the earliest that has universal support for Google Play services, which now also includes what was once the Android software store, which might explain it use as the common cut-off point. API 19 apparently has 95% compatibility with handsets currently in use, whereas API 20 has 85%, API 23 (Android 6) has 63%, and API 24 (Android 7) has 37% — if I was not limited by my own handset I would still most likely choose API 20 or 21 as beyond that pint there is a huge tail-off if compatibility. Support for API 27-29 is basically statistical noise and I do wonder why so many new APIs are coming out that are well ahead of hardware support.

Using Gradle

Given my less-than-fond memories of Mavan, Gradle was something that I wanted to avoid — particular issues I had with it was its operational model of pulling down loads of stuff on the fly, but in the end there was simply no support or help. To make matters worse the command-line tools for my older version of the Android SDK would not create a suitable boot-strap project, and new project functionality seems to have been removed from the more recent SDK packages. I tried setting up a Gradle project manually, but ultimately the only way I was able to obtain something that functioned properly was to create an empty project in Android Studio and then strip out all the files that Gradle did not need to build the application.

To be fair the projects created with Android Studio included a good boot-strapping script, and I got to the point where I fully automated both the setting-up and complete purging of entire build environments — a from-scratch setup seems to pull down a gigabyte or two but with today's internet connections that is no big deal. This was useful when trying to setup build environments for other people who were involved in Android projects I worked on, and when done it means I can easily clear out everything that is not required for archival purposes.

Using Java

On the whole I quite like the Java language, but I have long-standing hatred of many of its other aspects such as its run-time and standard libraries, which extend to various modus operandi within the Java eco-system. Google did a very good job of trying to clear things up with the Android implementation of Java, although it was not possible to avoid all of the problems and short-comings. Nevertheless I have found Java programming for Android to be a lot better experience than Java on the desktop.

Exception handling

The article on exceptional programming which I wrote back in 2014 covers pretty much everything I have to say about exceptions, and in short it is one of the things that is badly botched in Java. In the vast majority of the cases that Java demanded I put in exception catching, there was not a lot I could actually do — they were situations where overall program logic ought to prevent their occurrence, and if they did actually occur it would typically be situations where I would have to abort the whole application anyway. To be fair Android-specific Java libraries pretty much don't use exceptions, with the unchecked NullPointerException being the only one I see on a regular basis.

Rampant sub-classing

The design pattern I see a lot for event handlers is to dynamically create in-situ an object, invariably with a single overridden method, such as that shown below. I am not actually sure whether this is prevalent in actual production code or is just the preferred way sample code within StackOverflow answers:

findViewById(R.id.sign_in_button).setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { switch (v.getId()) { case R.id.sign_in_button: Intent signInIntent = auth.getSignInIntent(); startActivityForResult(signInIntent, 666); break; } } });

Personally I much prefer to have the parent class handle the events explicitly, as shown in the second code snippet below, at least because it is a lot clearer that it is code that is separate from the function where it is defined:

public class MainActivity extends AppCompatActivity implements View.OnClickListener { @Override protected void onCreate(Bundle savedInstanceState) { SignInButton button = (SignInButton)findViewById(R.id.sign_in_button); button.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.sign_in_button: Intent signInIntent = auth.getSignInIntent(); startActivityForResult(signInIntent, 666); break; } } }

This is not always possible though, as I have come across cases where creating anonymous classes inline for call-back purposes is required.

Import headaches

Of all the programming languages I have used, Java seems to require by far the most number of import statements, and it is way ahead of the hand-full I would typically use in Python. Something like wxPython has a very shallow hierarchy and I typically would just import the whole wx module as a whole, but Java library paths are both very deep and often have long component names, so even with wild-card inclusion a lot of import statements end up being used. To make matters worse, the documentation sometimes does not make it clear where a particular class belongs, which is a particular headache with the Google Sign-in and Google Maps libraries. I don't know if Android Studio has special features for finding out the classpath for a given object, but if it did it would be treating symptoms rather than the underlying problem.

Proliferation of source files

With Java public classes need to be in their own source file, so unless a program has everything in a single source file, the program ends up being spread over a potentially very large number of small files. For those who use their own text editors rather than an IDE geared towards having a lot of files, this can easily become a major pain to contend with. It also contributes to the next problem of deep source directory structures.

Deep directory structures

It is standard practice for Java source files to have a directory structure that mirrors the class hierarchy, and with the inducement to use a lot of small source files, this out of necessity is deep rather than flat. Understandably from a conflict-resolution point of view, Java has the practice of prefixing an organisation's domain name to package names, but this adds somewhere between two and four extra levels to already-long classpaths. Add in the hierarchy that Gradle imposes, and things go completely overboard:

Directory structure

~/Android
Somewhere to keep all Android-related stuff
~/Android/SDK
SDK files. I also rig various enviornment variables such as and paths so that things like Android and Gradle settings end up in here rather directly in my home directory.
~/Android/Project1
Base of Android project, as created by Android Studio.
~/Android/Project1/App
Application within project. Most of the time there will just be one.
~/Android/Project1/App/Module
Module within source. Again, most of the time there will just be one.
~/Android/Project1/App/Module/src
Base of source tree. With the older Ant-based build system there was none of the above and this directory was the first level.
~/Android/Project1/App/Module/src/main
Main “product variant” — other variants could be things like debug.
~/Android/Project1/App/Module/src/main/res
Resource files, such as XML-based screen layout definitions and icon files.
~/Android/Project1/App/Module/src/main/java
The Java source files, which itself has its own hierarchy.
When I got Android Studio to auto-generate some template files for a test project, I ended up with paths like the following:

~/Android/Project1/App/Module/src/main/java/uk/org/remy/myapp/ui/MainActivity.java

I ended up flattening the Java source portion of this hierarchy because it was simply too much of a pain to deal with, especially for projects where I started out with a provisional base package name which was later changed to a project-specific domain.

Variable shadowing

In Java the this operator for accessing class-local variables is optional, so the class variable namespace overlaps with that of function-local variables. The usual convention is using a prefix such as m_ on class variables, but personally I dislike such conventions in favour of being explicit. This is perhaps due to having a background in ADTs written in C prior to being introduced to Java object-orientated programming. In Python the namespace for local and class variables is explicitly separated by requiring the latter to be accessed using the self. prefix. This is partly a consequence of Python not requiring declaration of variables before use, but I think overall it leads to clearer code — one simply doesn't have to think about potential clash in variable names.

Thoughts on C#

C# was clearly inspired by Java, although it also borrows heavily from C++ in places, and like Java I think it is also a nice language. The problem with C# is the C#.NET eco-system — I gave up on the Mono after initial enthusiasm for it with Sprigfern Solver, and these days I simply have no time for Windows-based software development. Xamarin Studio tried to use C# as a common language for mobile development, but it seemed to sink without trace when Windows Phone exited the market.

Final thoughts

It is nice to get back into mobile programming, but I have mixed feelings about whether I would want to ever do it as a career. I feel the way Android is structured into activities which communicate using intents is nice, but as with GUI programming in general the limiting factor is knowledge of libraries and their short-comings rather than underlying programming ability. Compared to my favourable experience back in 2014 I feel that the Android APIs — especially the Google Play ones — are tricker than they ought to be to use, and getting appearance right at time feels more like website design than programming.