Publishing Android apps in the early years
October 3, 2016
I started on my first Android app two months after the platform’s 1.0 launch. I felt late to the party. Round one of Google’s Android Development Challenge had already concluded, and the five million dollar prize pool was already rewarded.
I figured it was still worth a shot. A colleague had made a bunch of money off of iPhone apps during the initial gold rush, including a few thousand dollars on a well-crafted tic-tac-toe app. I figured the same would happen on Android, and hell, I already knew Java.
When I got my Android Dev Phone 1 in December, 2008, I noted about 140 apps in the Android Market (the precursor to Google Play). The “Cards and Casino” section was quite light on content, and I had just spent two years working on poker and slot machine software.
There was no clear path to making any money at that point. The Market did not support paid apps yet, and there was no ad library. I figured the matter would be settled soon enough, and so another colleague (graphic designer) and I set to work on a simple slot machine game.
Documentation was reasonable, if a bit sparse. I worked off the original Lunar Lander example code. It had a lifecycle-related bug, which stayed open on the Android bug tracker for 6 years before someone finally marked it obsolete. I had considerable difficulty maintaining 30+ frames per second while still updating the view when I intended to. I remember being desperate enough that I tried calling draw() recursively. It worked great for a second or two! Perhaps the biggest technical achievement was a “pullable” lever that tracked the user’s finger.
Within about a month, we were ready to launch Beat The Joker Slots. We were the twelfth entry in the “Cards and Casino” category. AdMob had just published its initial SDK, and I set it up to refresh an ad every ten spins. The immediate results were striking, though it slowed down pretty quickly, per this email I sent to my collaborator:
“So in the first hour, it made $9. After 2 hours, it was at $15. Then it slowed down a bunch – 12 hours later, it has made $20. I blame this somewhat on admob having a bunch of repetitive ads, and also, they seem to have ran out of unique ads to serve to the user base, the fill rate (how often they provide an add when I ask for one) fell from 99% to 78%. However, we’ve already had 10000 impressions, which shows we really are getting decent volume. Latest count shows 1200 downloads, with a rating of 3.75 stars, which is pretty great for a game that I personally would get bored of in under 3 minutes.”
We settled into a pretty nice place, though. Beat The Joker peaked at #4 in its category. Along with a reskin (Zombie Jackpot Madness), we generated about $300 a month from Admob (and a few other advertising SDKs) for a solid three years. The two apps ended up with over 650,000 downloads combined. It’s pretty remarkable, considering how basic those games are. If I published them today, I doubt I could recoup the $25 I paid to open the developer account.
I didn’t know all that much about advertising then, but I saw a list of most valuable keywords on AdSense, and “mortgage” was one of them. I thus conspired to create Real Estate Droid, a front end for a half dozen real estate APIs I found. It included an auto-updating “show me the nearest home for sale” feature, which I thought was pretty innovative in early 2009. I included a mortgage aggregator’s quotes for a modest fee, and displayed Adsense ads in a WebView to get that valuable real estate advertising. The UI was completely un-styled and generally ugly. I didn’t have access to MLS systems, the most comprehensive database of US real estate for sale. However, it was the second real estate app in the Market, and hit 100,000 downloads in relatively short order.
Network requests were tougher back then. Real Estate Droid launched before Android Cupcake, the release that included AsyncTask. Developers often sneer at AsyncTask nowadays, and perhaps rightfully so. Back then, it was a godsend. Before AsyncTask, I needed to deal with Handlers directly for network requests, and there wasn’t a lot of advice online on how to get it right. (Never mind processing a SOAP API… I think that’s a pain even today.)
Updating a ListView asynchronously was even worse. List items get recycled as they move off screen, and if you’re not careful, you may end up overwriting a list item’s content when a response comes in for a request you issued during that item’s previous lifetime. The official Android Developer Blog addressed this issue a year later, but by then, I had already spent way more than my fair share of time figuring it out on my own.
Adsense served very valuable ads for a few weeks before I got banned. Six months later, I heard from an Adsense representative who personally invited me to integrate their beta Android SDK. Go figure. I learned that they had been upset that I was showing web ads in an Android app, but that was no longer a concern. I was back in business!
It got better. Admob and Adsense would both piloting new ad products from time to time, and they were both willing to make some financial guarantees to secure my participation. From my perspective, it seemed crazy – Admob had been acquired by Google, and it was as if they were competing against each other. From their perspective, I can only imagine that my royalties amounted to rounding error.
That was the high water mark for my app empire. If I had built a multi-game casino app, or a real estate app with a top-notch UX and partnerships with Realtors, I might’ve been able to keep growing. Instead, I focused on my day job, and better apps slowly ate my lunch. After a few years, API dependencies shut down and I unpublished Real Estate Droid.
Regardless, I consider the effort a huge success. My app income translated to an attractive hourly rate. When Android later became popular enough that every business was saying “Oh, and we need an Android app, too!” (2010), I became the lead mobile developer at my day job. In 2012, I joined the Android team at Google and became one of the founding engineers on the Project Fi. I was always a tiny bit starstruck whenever I ended up on an email thread with the engineers whose names I remembered from early Android. I continue to work at Google, though lately I’ve shifted my focus to Machine Learning. TensorFlow feels a lot like Android 1.0 did. Everything feels new, full of potential, and occasionally, a bit of a mess.
I’m going to work for Google
September 17, 2012
A few minutes ago, I accepted an offer to be a software engineer at Google. As you might suspect, I’ll be doing Android development.
With that decision, I am no longer available for contract work. I plan to maintain my blog with roughly the same irregular posting frequency as over the last 9 months.
This was taken at the Googleplex in Mountain View, California. Note the little green Android guy in front of the giant statue – Jenny knitted him for me!
Sample Fragment code available on GitHub
September 4, 2012
Tonight, I put together a simple Android project to get a better grip on the Fragment lifecycle as it relates to the Activity lifecycle, and to do some simple Fragment manipulation. I have used Fragments in past projects, but never from scratch, and setting this up was pretty illuminating. I annotated the source with explanations and relevant Stack Overflow links and pushed the project up to GitHub. The resulting project now lies here: https://github.com/goat000/FragmentDemo
Some of my basic findings:
- You can’t remove Fragments that were declared within your Activity’s layout file. You can only remove Fragments that were added programmatically.
- If you are going to add a fragment programmatically, make sure to inflate its view with inflater.inflate(R.layout.test_fragment, container, false); If you skip the third parameter, you’ll get IllegalStateExceptions that say “The specified child already has a parent.” It’s rather annoying, as the stack trace won’t lead back into your code.
- onActivityCreated is called for a new Fragment even if its Activity was created a looong time ago, and it’s called after onAttach. This seems peculiar – how do we attach to an Activity before it’s created? However, it doesn’t seem to hurt anything.
- Fragments that are added programmatically are retained across configuration changes, like rotating the screen.
- Fragments have their own onSaveInstanceState but no onRestoreInstanceState. You can restore the saved Bandle in onCreate, onCreateView, or onActivityCreated.
Please do let me know if you run into problems with this.
Handouts and Code for Android classes
August 12, 2012
I have uploaded the notes and code from the classes I taught at Montgomery College this summer. Check out the github repo if you are interested. I hope it will be of some use to anyone else teaching an Android class, though I do not recommend using this material to learn Android yourself.
Android has a sense of humor
June 2, 2012
According to Google, “Each major release of Android has a method or constant whose name is amusing or just silly.” Here are three I’ve come across:
For some time now, the Eclipse ADT Plugin has contained a logcat tab. This provides a (mostly) nicer way to view logs than executing “adb logcat” at the command line. This was not good enough for one developer, who opened an issue in Android’s bug tracker with the following text:
I would like the LogCat icon to be modified to a cat.
It would entertain me while developing and debugging.
For those not in the know, NyanCat gained a great deal of popularity on Youtube last year, and the original video now has 75 million views. Google came through, and as the first developers downloaded ADT version 14.0.0, they noticed the new, nyancat-inspired icon.
Yes, there’s a method in the Android SDK that will tell you if the current user is a monkey. It’s not quite what you think. Android includes a testing tool called “UI/Application Exerciser Monkey” that generates random interactions with your app as a sort of idiot test. I’ve found program defects with this tool that I don’t think I ever would have come across otherwise. isUserAMonkey() lets you know if “the user interface is currently being messed with by a monkey.”
In Android 2.2 (FroYo), the Android team introduced a new logging level higher than the previously-highest level, “e” (for error). According to the SDK documentation, WTF stands for “What a Terrible Failure” and is reserved for reality checks for conditions that should never ever happen. Depending on one’s development settings, a WTF() message may terminate an app immediately after it is output to the log.
I’ve always appreciated running into these. I know there are more (see fyiWillBeAdvancedByHostKThx) but I’m sure I’m missing a lot. Does anyone else know any good jokes hiding inside the Android SDK?
Where to hold Global application state in Android apps
May 9, 2012
I recently started working on a project with savvy apps and we came to a discussion about where to handle Global application state – a bit of information that you need to access pretty much everywhere. Here are the options I’ve thought of, and the tradeoffs involved.
Extend the Application Class
You can extend the Application class and add your own fields to the subclass. You specify your class in your manifest file with the android:name attribute without your application node. Then any context (e.g. Activity or Service) that wants to get to this information can call
Context.getApplicationContext() to get your Application object.
This is a reasonable way to store state that you’re okay with losing when the Application is destroyed. The documentation page for Application mildly discourages this use:
“There is normally no need to subclass Application. In most situation, static singletons can provide the same functionality in a more modular way. If your singleton needs a global context (for example to register broadcast receivers), the function to retrieve it can be given a
Contextwhich internally uses
Context.getApplicationContext()when first constructing the singleton.”
Fair enough, that brings to:
Plain-Old Globals Class
There’s really nothing wrong with have a class with a bunch of static fields that you get and set as needed. Just don’t hold onto any Contexts, or any objects that hold a reference to a context, like a View. Again, anything you set here will disappear when your Application is destroyed.
This is the way to go when you need information to persist across your app being destroyed and re-launched. SharedPreferences are a simple key-value store that you can access from anywhere that you have access to a Context. There’s a straightforward intro on the Android Developers site. Just make sure you don’t store things here that you DON’T want to persist indefinitely.
Avoid Global Application State
You should always cringe a little when you consider adding a “global” anything. It has its place, but it breaks encapsulation and adds complexity to your code – there’s always one more bit of information the code your working with COULD be dealing with, so there’s one more thing you need to keep in your head. Per the famous Mr. McConnell, we should always endeavor to structure our code such that working on any given chunk of it requires keeping track of as few things as possible.
The alternative to application state is often passing extras within the Intents that launch activities. If you’re writing a newspaper reader, you probably don’t need to store the current newspaper in a globally-accessible field. Rather, when the user clicks a newpaper to see it’s latest headlines, you pass in the newspaper ID as an Intent extra. When the user clicks a headline to see the article, you again pass along the newspaper in an Intent. The downside is that you have to add and read that bit of data to all Intents that care. The upside is that you have a better idea of what parts of your code are using what data. I generally prefer passing data around this way when I can.
Interviewing Programmers (Or: When FizzBuzz is asking too much)
April 22, 2012
FizzBuzz entered the software development lexicon in 2007, when Imran Ghory wrote a post about a simple programming problem that can weed out those who just aren’t very good when it comes down to actually writing code. The task: “Write a program that prints the numbers from 1 to 100. But for multiples of three print ‘Fizz’ instead of the number and for the multiples of five print ‘Buzz’. For numbers which are multiples of both three and five print ‘FizzBuz’.” If you can’t write that out in a few minutes, I don’t want to pay you to write code for me. As Mr. Ghory mentions, a depressing percentage of candidates can’t do this in a timely fashion.
This doesn’t surprise me. Thanks in no small part to this classic post from Joel Spolsky, I believe very strongly in making candidates program in their interviews. At my last job, my main role on interview day was to prompt candidates to code on the spot and help them along just enough to keep them moving when they got stuck. I always started them out with something even simpler than the FizzBuzz problem: “Print out all of the elements in this List” (it’s a Java interview). Most people got through it very quickly, and perhaps we’d go from there to a brief exchange about exception handling or the behavior of toString() and why every object will have that method defined. For some, it was problematic, but I’d give them a chance to print out elements of an array, or to do something similar in the language of their choice, and at least that would keep us moving. However, about 15% of my interviewees crashed and burned here. These people might possibly write decent code, when given an IDE with code completion hints, but if that level of coding isn’t fully burned in one’s brain after doing even a fair amount of coding in college, I don’t want to take my chances that said candidate will ever reach a barely-acceptable level of productivity.
These “immediate no” candidates had already convinced HR that they had sufficient qualifications for the position, and had already provided answers to specific technical questions I asked them on the phone. If not for the coding exercises, we would have made a couple of seriously damaging hiring mistakes.
Here’s my preferred interview structure for anyone that’s going to spend significant time mucking about in my code base. This assumes a position that will be doing web application development, but also a helping of “mad scientist” work – the kind of work that goes into building a revenue-optimizing ad platform or a search engine.
- Head of the department asks the soft questions
- One coder asks questions about high-level software design issues and specifics of relevant platforms
- One coder asks questions related to algorithms and data structures
- One coder (or perhaps two) asks the candidate to work through some programming problems
The specifics should be modified for the level of the position being discussed, and it’s not so important how the questioning is split up among interviewers. For recent grads, I’m not too troubled if they’re a blank slate when it comes to design patterns. For senior candidates, that’s not okay. (Side note: I don’t care so much if someone doesn’t know the names of patterns or can’t enumerate a bunch of them. I’m more interested in seeing if they can come up with a decent high-level design for a problem that a popular design pattern solves well.)
Do me a favor – tell me about your interview process, your worst interviews, or what’s wrong with my suggested interview schedule.
P.S. Bored? Check out this solution to the FizzBuzz problem. It has no branches and involves the number 19142723.
I’m teaching Android development at Montgomery College
April 12, 2012
I’m going to teach two courses on Android development at Montgomery College in Gaithersburg, Maryland in June and July (2012). These courses (fifteen hours spread across five sessions) are intended for students who have some Java experience (like one semester in college). The first course will focus mostly on laying out interfaces and responding to user actions. The second will build on the first, and will cover background tasks, maps and location, and interaction with the web.
Here’s are the links to the course descriptions: Android I, Android II.
The risks and rewards of offshore app development
March 13, 2012
There’s no lack of blog posts about offshore development strategy, so let me make this one quick and specific. I’m talking to those of you looking for a smartphone/tablet app, probably your first one. You don’t have a big budget because you’re really not sure if it will be worth it for you, and you’re not in a situation where $15000 (or $5000) adds up to rounding error. You come to me first, and I tell you I’m trying to make $90/hour or more. You’ve take a quick look at a freelancer site, and sure enough, there are a whole bunch of people willing to work for $20. Why pay 4.5 times the rate for a more experienced, U.S.-based developer? Honestly, there are times that going with the cheap guys is best. But in your situation, it’s probably not. For one, the best programmers work about 3 to 4 times faster than average ones.* Here are some questions you can answer to figure out if you should consider low-rate offshore developers. A lot of them come down to whether or not you need help decide what you really want, and whether you are capable of evaluating development work before disaster sets in.
- Do you know exactly what you want to build, and are you confident that your customers will like it? Do you know how you’ll make back your investment? An experienced app developer should have understanding of not just coding, but also user expectations and possible revenue models. The cheap guys probably aren’t going to be able to steer you in a useful direction (though they’ll promise you they can). Furthermore, a local developer should be able to meet you face-to-face, which is invaluable for talking through ideas.
- Are you an expert consumer of the platform your project will use? Android and iPhone apps have a lot of differences in their standard user interfaces. For instance, iPhone tabs go on the bottom of the screen, but Android tabs go on the top – and you should probably be using the “Action Bar” instead. If you go wrong here, users will take longer to get used to the app, and a lot of them will get frustrated and never settle in. The cheap guys may be able to point to an app where they did it right, but how sure are you that the same person will be working on your project
- Do you have have intellectual property or information security concerns? Anyone you trust with building your app could steal your code, your data, or any other IP you provide them. However, if someone does you wrong in the U.S., they know you might possibly be able to take legal action and make them pay for it. You might also have an opportunity to warm others in your niche about the shady developer, costing her business. If you answered yes here, the followup question is: are you prepared to sue someone in a foreign legal system?
- Are you confident that you can test all the use cases of your app? One of the big differences between a mediocre programmer and a good one is the ability to handle uncommon situations gracefully. Say you have a screen with a button that loads data and then shows it in a different screen. The normal use case will probably be pretty straightforward, but what happens if the user presses the back button while the data is loading? There are a bunch of ways to get that wrong, and many of them will crash your app. Your cheap guys may not think to handle it. You’ll have to know to look for those kind of things yourself, or you may have an app that crashes, loses data, slows down, or wastes battery.
- Can you judge the quality of the code you receive? Two developers might both be able to develop an app that meets your requirements, but one of them may do it by employing best practices under the hood, and the other may have used the digital equivalent of duct tape and spit. The difference will matter when you have additions made to it – a well-designed app will be easily modified and extended. A poorly-designed app may take three times the effort (or you might have to trash it and start over). Speaking of which…
- Do you have any plans to expand your app in the future? Even if the cheap guys write decent code, how likely do you think they are to be around when you come back 6 months from now? I can’t say they won’t be, but I wouldn’t count on it. If they’re not, you’ll have to vet developers again, and they’ll need some time to get up to speed on the existing work.
- Do you need someone to write culturally-aware English? I’m not talking about offending people because of deeply held values. I mean picking the right tone of voice, with common grammar constructions, so that the text looks natural.
- Do you need to get in touch with your contractor during your local business hours?
If you’re still not deterred, go ahead and give a low-cost freelancer a try. It has worked out well for plenty of companies. Just remember, sometimes “cheap” is the most expensive option.
* This link is to a rather wordy post and you’ll have to get halfway through before you see the bit about measuring productivity. However, the article has loads of other good information on why it’s worth it to hire the best coders despite the cost.
Improve your software developer job post
March 5, 2012
A few weeks, a hiring manager on Reddit asked the readers of cscareerquestions were they look for jobs, and expressed frustration with the developer candidates HR sent his way. The developers sent up a few guesses about why the hiring process was going badly for him. Maybe your HR people are filtering based on simple keyword searches because they have no idea what the position actually does. Maybe you’re doomed because you’re looking for C++ developers in a city where the only other C++ work (high frequency trading) pays extremely well. Maybe it’s your job description.
He posted the job description. It was definitely the job description.
Here’s an excerpt:
“The software developer’s role is to design, code, test, and analyze software programs and applications. This includes researching, designing, documenting, and modifying software specifications throughout the production lifecycle. The software developer will also analyze and amend software errors in a timely and accurate fashion and provide status reports where required. ESSENTIAL FUNCTIONS: Strategy & Planning • Assist other developers, analysts, and designers in conceptualizing and developing new software programs and applications. • Plan phases of the software development life cycle (SDLC) for a variety of projects. • Assist in the preparation and documentation of software requirements and specifications. • Research and document requirements of software users. Acquisition & Deployment • Conduct research on emerging application development software products, languages, and standards in support of procurement and development efforts. • Recommend, schedule, and perform software improvements and upgrades. blah blah blah blah BLAH BLAH BLAH BLAH BLAH BLAH”
Yes, it was formatted just like that, too. But formatting aside, what’s wrong with this? I bet it describes the position accurately. It also describes every other software development position on the planet. (Don’t believe me? Google any of the sentences in the excerpt above and see how many postings use those exact words.) This posting went on for another hundred words or so before it finally mentioned ANYTHING specific to the position. 3 characters, “C++”.
Don’t put anything in the job description that I already know! Solid candidates aren’t interested in reading a description of a what a software engineer is. They want to know what the job is like and why yours is better than the others they are considering. Drop the bit about modifying software to meet business requirements, or the necessity of working well individually or in a team. Instead, tell me:
What project will I work on? Is it fun? Will it make a positive difference in people’s lives? What will I learn while I’m doing it?
Is there any proof that the existing team is any good? Maybe you have a nifty product already in the Market, or your lead dev speaks at conferences.
Are you willing to pay to get the best coders? If so, speak up! N.B. The only thing “Market” or “Competitive” suggests is that you don’t pay a top-end compensation package. It transmits no other useful information.
Does the hiring manager have actual technical knowledge?
Is there beer in the fridge? Do people like each other enough to hang out after work?
Does your company have any personality? Can you break through the Office Space-style language enough to show that a thinking human being wrote this, and a thinking human being will read my resume?
If you don’t know the answer to those questions, go back and talk to the development team. Maybe even ask the junior ones, the ones who aren’t yet fluent in corporate-speak. Ask them why they work at your company. If they have a decent answer, that’s your job post. If they don’t, you’ve got a much bigger problem.