Android Development — The Good, the Bad, and the Ugly

Sebastian Deutsch
6 min readMay 13, 2016

--

Dear Android Community… It’s time to talk… It’s not you; it’s me — we need to sort some things out. To be honest, I’ve been off the grid with Android development for a while. Last time I’ve developed for Android, the new Android Studio Beta was just released and most developers were still using Eclipse. For the last two months, I was developing a greenfield app. Developing something completely from scratch is really cool because you get the chance to reevaluate all your best practices, and try some entirely new ones. These are the topics I’m going to cover in this post:

I wanted a nice ORM
I needed a nice abstraction to read from APIs
I wanted my app to be maintainable and well structured

The Bad: Game of ORMs

In my last app, I’ve used GreenDAO as ORM — which was quite ok. Updating the app was sometimes a bit of a pain, and the whole code generation made me feel dirty. Everything gets even more complicated with the automatic imports from Android Studio because it regularly breaks your GreenDAO models. So, I decided to go with ActiveAndroid since it was recommended to me a few times (one of my colleagues is using it in another app) but soon I ran into problems. I’ve got a null pointer exception on a fresh project. It seems like the author of ActiveAndroid is not that interested in solving the problem (even though there are fixes out there) so I abandoned this library. My next idea was to ask the crowd for help, so I turned to Twitter. My peers on Twitter were so kind to give me some recommendations — but actually, I was quite shocked. It’s been around four years since the last time I wrote my last Android app — and from all the ORM libraries no clear winner emerged? Srsly??!!

Eventually, I went with Realm, which was an OKish decision but I’ll get to that later.

The Good: API

Retrofit by Square is the gold standard when you’re dealing with JSON-APIs. Setting it up is fairly easy. You add some dependencies to your gradle file and you’re good to go. The next step is to generate some models with the help of this nice website. Now, I have two types of models: 1) JSON to POJO 2) REALM to POJO. I tried to merge them using this little helper, but I failed at a very basic point: When reading from an API you just have the possibility to update the whole Realm object. It’s not possible to partially update the Realm object depending on fields that are just set in the JSON. It’s sad to see that this feature is actually requested but buried in a backlog. Also there are simple tasks like sorting a child collection which is simply not possible yet.

The Good: A well-structured app

My app already has a few components: Realm, GSON, Retrofit, OkHttp. Many of these are global singletons. When I did some iOS development we used the Factory Pattern together with a central registry to achieve some well-structured code. In Android land, there’s something similar: It’s called Dagger 2 — unfortunately, grasping all of its concepts takes a little time. The official docs are IMHO a little too dense. Luckily, Jake Wharton gave a really really really great talk that explains everything. Unfortunately, you have to register to see the whole video, but it’s 100% worth it.

The Bad: A tale of ContentProviders

My application is about sharing images. I needed to store these bitmaps in the filesystem (or somewhere else). I decided to ask the Google+ Community for a best practice.

The only answer I got wasn’t that helpful. So I had to RTFM and figured out that there are two options:

  1. Save them on the external storage (more permissions needed)
  2. Save them on the internal storage

I really wanted to go with the second option (because fewer permissions lead to more installs), but files from the internal storage can’t be shared with other applications (Facebook, Twitter, Snapchat). Unless… After some time I found a way by creating a ContentProvider.

And while implementing this I realized that it’s ALREADY IMPLEMENTED in the support library.

After wiring the FileProvider, I’ve noticed that my app doesn’t work on the Emulator anymore. I’ve got an IllegalStateException:

java.lang.IllegalStateException: Couldn’t read row 0, col 0 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.

Googling the problem wasn’t very helpful.

I was close to tears and thought that I’d have to go with the external storage when I stumbled upon this StackOverflow post. Eventually, I found an implementation that actually works:

What a ride!

The Ugly: Google Analytics

I thought that adding Google Analytics to my app would be pretty easy. First, adding some dependencies to gradle. Then wiring a tracker singleton in Dagger 2. After that, salting my Activities with some tracking events. And finally, downloading a google-services.json with my application parameters. That’s got to be easy, right? Nope, it’s not! On the first page I’ve added a new application but I wasn’t able to select the correct Google Account on the next page to wire up analytics with the correct property. It took me about half a day to figure out what was going wrong. I needed to remove me from all other accounts before I could add the desired one.

The Ugly: Android Studio

Eclipse was a real pain — and we were delighted when Google decided to bless us with a better IDE. But while other Google Products are getting some real love, Android Studio seems to be a problem child. Let’s take the “Instant Run” feature as an example: My app is simple. It’s about sharing stickers in social media apps. It has two activities, one API service and a bunch of models wired with Dagger 2. WHY IS INSTANT RUN NOT WORKING 100% OF THE TIME? WHY DO I HAVE TO RUN THE APP TWICE TO ACTUALLY RUN IT? When I asked my peers, they told me to turn off Instant run. Why would you ship a feature that doesn’t work? Don’t do that! If you want to learn more about Instant Run and why it’s terribly inferior then you should also read this post which compares JRebel to Instant Run. Another pain point is working with custom libraries — how often I had strange errors where a “Invalidate Caches / Restart” solved the problem.

The Good: Google Test Lab

It was the first time for me to work I with Test Lab and I was impressed how quick it yielded results from a wide variety of devices. You’ll be notified of exceptions together with a logcat and even a video that reproduces a problem. Kudos Google!

The Takeaway

Some parts of this post might look like a rant and maybe they are. But I want to give some constructive advice:

To the open source maintainers:

Be honest with yourself if you’re not able to maintain your project anymore: mark it as deprecated. If you’re doing something else: mark it as deprecated. If you’re not ready to kill your baby ask for help in the community. Code is not the only part of success — the community is as much as important.

To Google:

If you really want to push Google+, then please invest in your community. The only comment that I got when I asked for best practices was not helpful. There shouldn’t be any stupid questions.

It’s a sign of poor documentation management that some external company does a better job on linking to the best practices than you do. Maybe you should move from Java to something else even if you have invested heavily in Java 8 with Android N.

You should create a little side event at I/O where you invite all the creators of great libraries to give them the chance to talk to each other. I’d love to see the Retrofit guys talking to the Realm guys while the GSON guys are listening.

I hope you enjoyed my report about the current state of Android Development although I left out some really thriving topics like RxJava or even Agera. If you like what you just read, you should follow me on Twitter, and if you think that you’re a better Android dev than I am (which is, let’s be honest, pretty likely) then you should apply at 9elements — we’re hiring.

--

--

Sebastian Deutsch

Heavy tech nerd. Founder of 9elements. Loves to talk about startups & entrepreneurship.