I just recently released my first Android application, Tippy Tipper, a tipping calculator. From writing this app I learned a number of things as a new Android developer and decided that I should write down and share some of these tips and tricks for other new Android developers who might come across them. My application is open source and you can find the source code at its Google Code project site here. My hope is that someone else can benefit and learn from what I have gone through these past couple of months.
Choosing an application to build
What should you write? Well, that is up to you, but if this is your first Android application then my recommendation is to choose something simple. You may know Java, but you do not know the Android framework. Gently ease yourself into the Android framework instead of creating a lot of frustration and headaches as you attempt to do something overly complex when you do not even grasp how layouts work. I recommend creating an application that you should be able to complete within a month or two at most, because once you complete this simple application you will have a sense of accomplishment which will encourage you to build something even more difficult and challenging. This positive reinforcement will keep you from burning out early in frustration. You essentially want to aim your application a couple of notches beyond the Hello World app.
Personally, I chose a tip calculator for a few key reasons:
- Tip calculators are common, so there are a lot of examples out there. I can learn from other people’s UIs and see how I can make mine better
- I wasn’t happy with any of the available tip calculators on the market
- I can use it, nearly every day. Therefore, I can dog food my app
- It is simple and covers most of the Android basics: 20 buttons (event handling), preference, multiple activities, etc.
How I designed my application
My approach to my Android app was to try and fit it into a MVC (Model-View-Controller) design pattern. In Android, the Activity classes act as both the View and the Controller. It behaves as a View because it renders the layouts to the screen and it behaves as a Controller by adding event handlers (onClick(), etc.) to objects in the View. The last piece is the Model, which in my case is a completely independent service (not an Android service, I simply am calling it a service in general) that provides functions to access and manipulate data (calculate tip, get the tip amount, split the bill, etc.). My service is stand alone and therefore easily unit tested by JUnit. For the most part, the UI of my app simply calls functions found in my service and then updates the View with new information from my service.
MVC Example
On the first main activity of the application (the keypad screen) we have an EditBox that shows the current entered BillAmount and some buttons (0-9) to append to the BillAmount, delete the last digit of the BillAmount, or to continue to the next Activity.

1 2 3 4 5 6 7 8 9 10 | ... <EditText android:id="@+id/txt_amount" style="@style/BillAmountEditText"/> ... <Button android:id="@+id/btn_five" style="@style/CalculatorButton" android:text="5" /> ... |
When you click the “5″ button, the following event handler is called:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public void onCreate(Bundle savedInstanceState) { ... View btn_five = findViewById(R.id.btn_five); btn_five.setOnClickListener(new OnClickListener() { public void onClick(View v) { AddBillAmount("5"); } ); ... } private void AddBillAmount(String number) { TippyTipperApplication appState = ((TippyTipperApplication)this.getApplication()); appState.service.AppendNumberToBillAmount(number); BindData(); } |
The AddBillAmount gets the instance of the service (more about this below, see Global Singleton) and calls the service’s AppendNumberToBillAmount():
1 2 3 4 5 6 7 8 9 10 11 12 | public void AppendNumberToBillAmount(String number) { if(BillEntry.length() < 15) { BillEntry = BillEntry + "" + number; } double amount = Double.valueOf(BillEntry); amount = amount / 100; BillAmount = amount; BillAmountBeforeTax = BillAmount; } |
Which appends the number to the end of our service’s BillEntry string and then converts it into a double amount which is saved to BillAmount and BillAmountBeforeTax. Now the Controller will call BindData (ASP.NET term; I’m a C#/ASP.NET developer by day) which will refresh our View with the service’s updated BillAmount:
1 2 3 4 5 6 | private void BindData() { TippyTipperApplication appState = ((TippyTipperApplication)this.getApplication()); EditText txt_amount = (EditText)findViewById(R.id.txt_amount); txt_amount.setText(appState.service.GetBillAmount()); } |
Viola! A simple MVC pattern put to good use. Now we can easily take out Model/service and apply unit testing to it:
1 2 3 4 5 6 | @Test public void AppendNumberToBillAmount() { TipCalculatorService service = new TipCalculatorService(); service.AppendNumberToBillAmount("1"); assertTrue(service.GetBillAmount().equals("$0.01")); }; |
Global Singleton
One of the first problems I had with my Model was always having a singleton of it available. An important thing to note with Activities is that they are destroyed and re-created whenever the user rotates their phone from vertical to landscape or vice-versa. Therefore, if you declare a singleton inside of you Activity, then it will be gone when the Activity is re-created. The workaround for this is to instead create the singleton at the Application layer, making it globally accessible to ALL activities.
First you have to create a class that extends Application and contains your singleton:
1 2 3 4 | public class TippyTipperApplication extends Application { public TipCalculatorService service = new TipCalculatorService(); } |
As seen earlier, you now simply have to get an instance of the Application in order to access your service:
1 2 | TippyTipperApplication appState = ((TippyTipperApplication)this.getApplication()); appState.service.AppendNumberToBillAmount(number); |
Using Preferences
Creating the preference activity is perhaps one of the easiest things to do in Android. You simply have to create a layout and attach the Layout to a class that extends PreferenceActivity:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public class Settings extends PreferenceActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.settings); } public static int getDefaultTipPercentage(Context context) { return PreferenceManager.getDefaultSharedPreferences(context).getInt("default_tip_percentage", 15); } .... } |
So long as you don’t need a custom dialog, then Android handles the saving/loading of dialog values for you in the background. In order to retrieve the preference value:
1 | double defaultTipPercentage = (double)Settings.getDefaultTipPercentage(getBaseContext()); |
But what if you do need to have a custom preference dialog?
Creating and using a custom preference dialog
For setting the default tip percentage values, I wanted to use the SeekBar similar to how it is done on the Activity in which you choose a tip percentage:

No such thing exists in the Android SDK so I either had to create my own or see if someone had already made their own. Thankfully, someone had already made a SeekBar preference.
The key important thing to rolling your own custom preference dialog is knowing how to get your stored value:
1 2 | if (shouldPersist()) mValue = getPersistedInt(mDefault); |
And updating your stored value:
1 2 | if (shouldPersist()) persistInt(value + mMin); |
Extending preference with min value (How to add attributes to your widgets)
When I originally used the SeekBarPreference, I was also using it for the preference dialog of setting the default number of people to split the bill by. This means that the SeekBar has to go from 2 to max_value, instead of 0 to max_value. So I had to extend the SeekBarPreference to allow this. My first problem was that the Android name space does not have an android:min defined, only an android:max.
I have to create a min attribute in a res/values/attr.xml file:
1 2 3 4 5 | <resources> <declare-styleable name="SeekBarPreference"> <attr name="min" format="string" > </declare-styleable> </resources> |
Then I have to reference the namespace in the Preference layout:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <PreferenceScreenxmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res/net.mandaria.tippytipper"> <PreferenceCategory android:title="Tipping Options"> <net.mandaria.tippytipper.preferences.SeekBarPreference android:key="default_tip_percentage" android:title="Default Tip Percentage" android:summary="Percentage to tip by default" android:dialogMessage="Percentage to tip by default" android:defaultValue="15" android:text="%" android:max="40" app:min="0" /> ... |
Finally, to get the min value programmatically:
1 2 3 | private static final String appns="http://schemas.android.com/apk/res/net.mandaria.tippytipper"; TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SeekBarPreference); mMin = a.getInt(R.styleable.SeekBarPreference_min, 0); |
Note the usage of the TypedArray against the attrs.xml file created above. This is different than grabbing android:max programmatically (I could simply be missing something above, but it works):
1 2 | private static final String androidns="http://schemas.android.com/apk/res/android"; mMax = attrs.getAttributeIntValue(androidns,"max", 100); |
Android is missing the NumberPicker widget in the SDK
For whatever reason, the NumberPicker widget is not publicly available to developers. It is there, but it is hidden in the internals of Android and I didn’t want to access private APIs by finding it by reflection. Instead I found it in the Android source code and was about to pull it out when I found that someone else had already beat me to it.
I really do not understand why this widget is not publicly available, because forcing a user to only select an integer value is very nice (with the ability to enter the integer with the +/- buttons or typing it in).
I used the NumberPicker in my own custom dialog preference called DecimalPreference:

Using LDPI, MDPI, and HDPI with Android 1.5+ (How to set a min API and have a higher target API)
In order to get my app’s launcher icon to work with multiple DPIs (LDPI, MDPI, and HDPI), a feature of Android 1.6+, and to have my app still work on Android 1.5 phones, I had to set the app’s minSDK value to 1.5 and set the targetSDK to 1.6:
1 | <uses-sdk android:minSdkVersion="3" android:targetSdkVersion="4" /> |
Applications with multiple versions (free / paid / donate)
If you plan on having more than one version of your app, then it must be noted that they MUST have different package names on the Android Market. I did not realize this until I was ready to release and had to spend about an hour or so creating a Donate branch in my SVN and renaming the package references everywhere from “net.mandaria.*” to “net.mandaria.tippytipper.*” and “net.mandaria.tippytipperdonate.*”
I feel like my Donate branch isn’t the best idea. For every release I will have to merge the trunk into the Donate branch and rename the package from “net.mandaria.tippytipper.*” to “net.mandaria.tippytipperdonate.*” and I cannot think of a better way to do it. Any suggestions?
Reporting error handling
One thing I have yet to implement is reporting any errors thrown in the app by users to me. The Android Remote Stacktrace project looks promising, but I would have to enable internet privileges in my app when it does not need them otherwise (how acceptable is that?). Or I could create an e-mail intent on errors (but that is less anonymous and they may be less willing to submit the report). Any thoughts on this?
PayPal API == Better way to donate?
PayPal just recently released an Android API for making PayPal transactions inside of apps. This could be an alternative way to collect donations for an open source app instead of (or in addition to) dealing with a second donate version of the app. But it could also potentially break the Developer’s Distribution Agreement:
3.3 You may also choose to distribute Products for free. If the Product is free, you will not be charged a Transaction Fee. You may not collect future charges from users for copies of the Products that those users were initially allowed to download for free. This is not intended to prevent distribution of free trial versions of the Product with an “upsell” option to obtain the full version of the Product: Such free trials for Products are encouraged. However, if you want to collect fees after the free trial expires, you must collect all fees for the full version of the Product through the Payment Processor on the Market. In this Agreement, “free” means there are no charges or fees of any kind for use of the Product. All fees received by Developers for Products distributed via the Market must be processed by the Market’s Payment Processor.
Technically, the donation is not required for use of the Product as it is still provided 100% free. But it isn’t being processed by Google’s Payment Processor. So I do not know whether or not to explore this route.
Conclusion
I’m very excited about Android. I’m very happy to now be a part of its developer community. I’m still very new at it and am learning something new every day. I hope that these comments of mine help someone else, or if any of them are totally wrong, please feel free to correct me. I appreciate all the constructive criticism I can get to improve both my application and myself as a developer.
Tuesday, May 25th, 2010 at 1:48 amand is filed under android. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.






May 25th, 2010 at 6:21 am
> I would have to enable internet privileges in my app when it does not need them otherwise (how acceptable is that?)
I own an Android phone, and I’d say users wouldn’t mind that at all. These days, I’m actually surprised when I see an app that doesn’t require Internet access.
By the way, how did you start on Android development? What resources did you use to learn about it? Where you on a Windows or Unix environment? Do you own an Android device? Did that make a difference?
That’s a lot of questions, but hopefully they’ll help many others too. Thanks for the post.
May 25th, 2010 at 7:52 am
> By the way, how did you start on Android development?
After installing the SDK, the first thing I did was get the Hello World sample app up and running. I actually used the Hello World app as a starting point for my Tipping Calculator.
> What resources did you use to learn about it?
If you’re looking for a book, take a look at Hello Android: http://www.amazon.com/Hello-Android-Introducing-Development-Programmers/dp/1934356492/ref=sr_1_1?ie=UTF8&s=books&qid=1274791568&sr=8-1 This book will run down all the basics of Android while building a simple Sudoku app. I also have the book Professional Android Application Development, but haven’t fully read it yet: http://www.amazon.com/Professional-Android-Application-Development-Programmer/dp/0470565527/ref=sr_1_1?ie=UTF8&s=books&qid=1274791653&sr=1-1
> Where you on a Windows or Unix environment?
Windows. I used Eclipse, so the experience should be the same for Windows/Unix/Mac.
> Do you own an Android device?
Yes. I have a Motorola Droid that I bought back in November. I don’t have any other physical devices to test with (all of my friends have Droids too). The emulator works decent enough for testing against other phone resolutions, but it is always better to test it on actual hardware. I’ve considered buying a cheap G1 off of eBay just to have both a “bottom of the barrel” phone and something more recent with the Droid.
> Did that make a difference?
Yes. Having a real phone is 100% faster than the emulator. You don’t have to wait for the emulator to boot up, and you can test against live things (GPS/camera/data access) if your app uses them. Plus the emulator is not 100% perfect. As I said, it is always better to test against a hardware phone.
May 25th, 2010 at 9:01 am
Oh, I also recommend http://www.stackoverflow.com as a fantastic resource. That’s where I found out how to do the Global Singleton.
May 25th, 2010 at 10:57 am
You don’t have to boot up the emulator everytime you want to test a change in the code, just leave it running and run the application as “android application” in eclipse. It will install it over the old version and start running in
May 25th, 2010 at 12:58 pm
> You don’t have to boot up the emulator everytime you want to test a change in the code, just leave it running and run the application as “android application” in eclipse. It will install it over the old version and start running in
Yes true, but for some people (depending on their PC’s hardware) that first boot might take quite some time. Or if you need to launch multiple emulators to test multiple resolutions at the same time.
May 25th, 2010 at 1:22 pm
Android version 2.2 adds error reporting feature on force close. Take a look at this. http://www.youtube.com/watch?v=IY3U2GXhz44#t=29m48s
May 25th, 2010 at 1:38 pm
[...] any who are curious, I also wrote about the things I learned from writing this [...]
May 25th, 2010 at 2:54 pm
> Android version 2.2 adds error reporting feature on force close.
I saw that and it looks nice, but what about everything pre Android 2.2? Plus, the reporting is voluntary by the user.
May 26th, 2010 at 8:58 pm
Nice article! I definitely concur with one of the initial assertions, to “start simple.” It’s easy to get lost in the many different options the SDK provides you, especially when you open up the door to graphics. Either way, thanks for sharing your experiences.
May 26th, 2010 at 11:32 pm
[...] WHAT I LEARNED FROM WRITING MY FIRST ANDROID APPLICATION [...]
May 31st, 2010 at 3:00 pm
[...] What I learned from writing my first Android Application On getting started with Android [...]
August 22nd, 2010 at 11:47 am
Hi, thanks for sharing.
Number Picker hack you added saved me lot of time.
Values are not updated when you use the keyboard (without using the button up or down).
Your workaround was to “click” the NumberPicker (onClick())
5* to Tippy Tipper on the market
August 22nd, 2010 at 2:48 pm
> 5* to Tippy Tipper on the market
Thanks! Glad my code helped you out!
February 23rd, 2011 at 4:25 pm
You lost me on the singleton method to avoid phone rotation trouble. I found that you can change the orientation of the application on a screen by screen basis in the AndroidManifest.xml by including the “android:screenOrientation=”portrait”
February 25th, 2011 at 11:00 am
@tbetz You’re only circumventing the problem. Disabling rotation may not be desirable in your application. Some devices may be more comfortable in a different orientation (think about tablets, they are preferably used in landscape). If you want to allow screen orientation, then you have to understand that in the lifecycle of an Android application, rotating the device will destroy the current activity and re-create it in the new orientation. Therefore, you have to keep (permanent) state outside of the activity, either in a global single (temporarily permanent for the duration of the whole application’s life), a local database, or a stored preference.
March 5th, 2011 at 2:02 pm
[...] site and you can find the source here: http://code.google.com/p/tippytipper/ I also wrote a blog post about what I learned from writing Tippy Tipper.Thanks a lot r/android! I really appreciate your [...]
March 5th, 2011 at 2:02 pm
[...] site and you can find the source here: http://code.google.com/p/tippytipper/ I also wrote a blog post about what I learned from writing Tippy Tipper.Thanks a lot r/android! I really appreciate your [...]
August 2nd, 2011 at 8:02 pm
Nice write-up! We are the developers of “Word Crank” a new Android App. Please check out the stats on our first week on the market. Very encouraging to see how far your app has come. Any further advice would definitely be appreciated. sivarttech.com
August 29th, 2011 at 8:12 pm
I have been attempting to do this to my own Personal computer but I can not seem to do it. Have you any idea of a great pc place that may complete this for me?
September 2nd, 2011 at 4:08 pm
Very good tutorial, one critic if I may is to use the Java convention in your code.
A Java method name starts always with lower case letter, it makes it easier for others to read Android code (Java). The first letter in capital is for class names.
Keep up the good job.
J
November 1st, 2011 at 10:33 am
Have you been able to make any money off of your app or any other apps you’ve written? just curious how the market is…
November 1st, 2011 at 10:36 am
@Ryan I’ve since developed another app, Car Dashboard https://market.android.com/details?id=net.mandaria.cardashboardfree&feature=search_result which does make a small income every month. Anywhere from $400-500/month (before taxes). It isn’t enough to replace my day job, but it is a decent supplement of extra money.
December 25th, 2011 at 3:57 am
Whosoever you are, this is awesome. I was looking for this article for a long time but could not find it. I am a .net developer and like you like to explore things.
Thanks for the great article.