One Simple Trick That Will Save You Hours When Developing Android Apps
./generate.py --package com.mycompany.myapp --screen Login
One of the things new Android developers learn pretty quickly is that sometimes if you want to make something, you have to make many things. Create a new activity. Maybe create a fragment or two for the activity to use. Create layout files for each of those. Whew! Oh yeah, don’t forget to add your activity to the app manifest (don’t worry, we always forget too). When you start building bigger apps you might start having view models or start using Dagger to help ensure things get wired up in all of the right ways. Don’t forget to make sure things are being called during all the right lifecycle events too (Android loves its lifecycles…). Maybe you want to also add in some unit tests or Espresso tests. After a while, something as simple as just adding a new, blank screen to an existing app ends up being lots of work, not easy to get right, and there is a painful amount of necessary boilerplate.
What if you could skip all that work and create everything in just a few seconds?
Rewind to several years ago when I was helping to kick off a new Android project with our team. We had decided to scaffold out all of the screens in the app and include navigation early so the client could get a feel for the user flow. So we started by building out one screen with all the parts we knew we would need. And then another screen. By the time the third screen was ready to build, we were several hours into this task and still had a dozen more screens to go. The rest of the next few days were not going to be much fun.
“There has to be a better way to do this!?!?” (My profanity removed)
When we paused to see if there was a better way, there were a few things we learned. First, there wasn’t much we could do to remove the boilerplate without making other goals (ex: test automation) much more challenging or adding in needless complexity. Second, we noticed that only a few things were different between all of the files we were creating or updating: file names and directory locations, class names and imports, and additions to the app manifest and Dagger configuration. Digging a little deeper, the only thing that was actually changing was some minor casing variations (ex: “PurchaseConfirmation”, “purchase_confirmation”, “purchaseConfirmation”, etc.).
What if we could create a tool that accepted a few variables, created all of the needed permutations, and then created files in all the right places?
We started by looking at Live Templates in Android Studio, but those only work inside a single file and we were touching lots of files for every screen. Next, we looked at creating an Android Studio plugin to help but we didn’t have the immediate capacity for that ramp up time and also didn’t want the ongoing cost of maintenance (not choosing a plugin has paid other benefits that I’ll point out later). All we actually needed was a script and a templating engine…so, let’s make a script and use a templating engine. Once we started going down that much simpler direction, I remember laughing and thinking “this thing is going to be so stupid it might just work.”
So we started by listing out of all of the “screen name” permutations we would need, took a diff of the files modified with the last screen we added and replaced the appropriate parts (ex: class name prefixes, package names, imports, etc.) with template placeholders. Given all of the template engines out there, we picked Mustache because we did not want logic in the templates to force simplicity. Not all of the files were new files; some needed to be modified. We decided to put in some “marker” comments that we could use to trigger string replacement on when we needed to add something new (ex: import, Dagger update, addition to the app manifest). Finally, we put together a simple script to read in all of the template files and write them out to some parameterized destinations and also update existing files with necessary snippets. That’s it!
After we ran our script for the first time and looked to see what it had generated we found that in under one second it had created and modified everything we were spending close to an hour per screen doing (including updating the app manifest!). After a few quick tweaks to the script and templates, we were able to build out the rest of the app screens in under two minutes and saved ourselves days of effort. Amazing! Beyond the saved effort, we were now confident that all of those screens are correctly built and we had a consistent pattern in our app architecture that everyone could feel at home using. Oh yeah, adding new screens in the future just got a whole lot easier.
We’ve since made a few minor updates to the script and templates, but because the script and templates live inside of each project they can independently maintain and evolve an architecture that fits that project’s needs. This is something that would have been a challenge to do with an IDE plugin. Internally to ensure there is no magic code that is hard to support, we still ensure new team members understand all of the implementation details of what gets generated.
Over the last few years and dozens of projects, this simple trick has saved our team and our clients countless hours of work. Ultimately, this is not a novel concept: lots of frameworks and tools already provide similar automation (ex: Rails, Angular, Yeoman). If those frameworks and tools don’t, however, this is a trick that you should be able to easily use on your non-Android projects too.
This is an approach that you can use and customize to fit your own project needs so you can focus on creating fantastic apps! If this is something that you find useful we would love to hear about it!
Feel free to take a peek at the script (https://github.com/atomicrobot/Carbon-Android/blob/master/app/generate.py) and the templates (https://github.com/atomicrobot/Carbon-Android/tree/master/app/templates/screen) we currently use on our projects. If you want to include them in your project, all you need to do is make copies and customize them to fit your needs. There are no dependencies or frameworks or other plugins to install (all by design).
If you want to see everything in action, check out this demo. Don’t blink…it’s fast!