5-3 TipCalculator App

At this point you should be getting comfortable with navigating Android Studio and using the basic tools it provides to build a user interface for an app.

For our next app, let’s make an interactive “Tip Calculator” that will look like this –>

Yes, it’s a pretty plain looking app, but it demonstrates a lot of important ideas in Android development.  I’ll leave it as an exercise for you to make it look better!

Creating a New Project

  1. Start a new Android Studio project.
  2. For the Application name: use “Tip Calculator”.  Leave the defaults for everything else and keep clicking Next until you get to the Add an Activity to Mobile  Choose Empty Activity (not Basic Activity) and click Next.
  3. On the Customize the Activity screen, for Activity Name: use “TipCalculatorActivity”. Don’t forget to uncheck Backwards Compatibility (AppCompat).  Click Finish and Android Studio will build the new project.

Designing the User Interface

Stop!  It’s always tempting to jump in and start building an interface or writing code, but professionals know that this always leads to extra work in the end.  It’s much better to sit down and plan things out on paper first so that we can think through how the interface should look and how the components will interact with each other in terms of their logic.  Also, even though this app is pretty simple, it involves a lot of different widgets, each of which need an ID (and a string resource associated with it) so that we can refer to them in our code.

To help us manage all of these details, and to have a clear picture of what we are building in front of us, I’ve sketched out the UI for the app.

The actual widgets are shown in black.  For each widget, I’ve labeled their ID property in red and their string resource name in blue.  This design sketch will be very helpful when we are writing our code and need to remember the name of a particular element of our UI.

For good style (and your own sanity!) it’s important to come up with a consistent naming convention for your widgets.  Above, I’m using the suffix “Label” for TextView widgets that will contain static text and “TextView” for TextView widgets that contain text that will change when the app is running.  For string resource names I am using pot_hole_case to differentiate them from widget IDs (using camelCase).  The main point here is to come up with a naming system that makes sense and be consistent about using it.

Creating the User Interface

Now that we have a clear picture of the widgets required for our app and how they will be placed relative to each other, we can use the graphical editor to build the user interface.

  1. Delete the default “Hello World” TextView widget from the interface.
  2. Drag and drop a TextView widget to the upper-left side of the visual layout.  Set its ID to billAmountLabel to match our design sketch.  Define a new bill_amount_label string resource for its text property as shown –>
  3. Repeat step 2 for all of the other 6 TextView widgets to match our design sketch: percentLabel, tipLabel, totalLabel, percentTextView, tipTextView, and totalTextView.
TextView ID String Resource Name String Resource Value
billAmountLabel bill_amount_label “Bill Amount:”
percentLabel percent_label “Percent:”
tipLabel tip_label “Tip:”
totalLabel total_label “TOTAL:”
percentTextView percent_amount “15%”
tipTextView tip_amount “$0.00”
totalTextView total_amount “$0.00”
    1. Next we need to add our interactive widgets.  The user will enter the amount of the bill using an EditText widget.  In the Palette tool window, in the Text group, drag a Number (Decimal) widget to the visual layout beside the billAmountLabel.  Set the ID to billAmountEditText, and set its text property to a new bill_amount string resource with a value of “0.00”.
    2. Finally, we need to add two buttons beside the percentTextView.  Drag and drop 2 Button widgets from Buttons group in the Palette tool window to the right of the percentTextView widget in our layout.  Set their ID properties to decreaseButton and increaseButton, and create “-“ (decrease_label) and “+” (increase_label) string resources for their text properties, respectively.
    3. To finish up, make sure to constrain the top and left sides of all of your widgets relative to each other or they will appear to overlap when you run the app.
    4. Once your initial layout is complete, try running the app!  You can actually interact with the billAmountEditText, decreaseButton, and increaseButton widgets but they won’t actually do anything (yet).

At this point you will have a pretty (ugly) interface for the app.  The key points are that all of the widgets from the design sketch have been added to the layout, that we have properly named them, and that we have created/associated string resources for them.

Layout XML Code

Below is the XML code (at this point) for our Tip Calculator app.  Consider this a guideline only!  Your XML will likely be different depending on how you defined the positions of the widgets relative to each other.  The main thing is that you have 7 TextView, 1 EditText, and 2 Button widgets defined, and that their android:text= and android:id= properties match our design sketch.  (You can scroll the code below, or click to expand it.)

Strings XML Code

Your app > res > values > strings.xml file should contain exactly these values, although the order might be different:

Double check that the name= property of each string matches our design sketch.

Java Code

Time for some Java!

Open the TipCalculatorActivity.java file.  It may already be available in a tab, if not you’ll find it in the app > java folder within a package for your app.  You’ll see the default starting code:

This class is created for you automatically when you start an app based on the Empty Activity template.  In Android, an activity defines one “screen” of your app.  Most apps consist of several activities, but we only have one so far.

On line 6, to define a custom activity, our TipCalculatorActivity class inherits from a class called Activity.  When an activity is started, Android automatically calls its onCreate() method and passes in a Bundle object.  The Bundle object is used to pass data between multiple activities – we’ll get into the details of this later.  Since we are creating a custom activity, we need to override the onCreate() method.

Line 10 ensures that the Bundle object is passed along to the parent onCreate() method first.  The setContentView() method is called to specify the layout for our activity.  Android Studio automatically maintains a special class called R (i.e., Resources) that provides a way to access the widgets and strings defined in our XML within our Java code.  On line 11, the R.layout.activity_tip_calculator refers to the activity_tip_calculator.xml file in our res > layout folder.

After these two lines is where we will add our custom code.

Referencing Our Widgets

In order to access the widgets in our application we need to declare and initialize reference variables for them:

On lines 7 to 9, we import classes from the android.widgets package corresponding to the three types of widgets in our app.  We will use the NumberFormat class (line 10) for locale-specific currency and percent formatting.

On lines 14 to 19 we declare private reference variables that we will use in our Java code to access the widgets defined in our layout.  It’s common to use the same names for these variables as the widget ID properties we set in the visual editor, but technically you can name them differently.

On lines 31 to 36 we use the findViewById() method, using the R class to obtain a reference to a particular widget in our interface by its ID.

Finally, line 39 calls the calculateAndDisplay() helper method to update the percentTextView, tipTextView, and totalTextView widgets based on the contents of the billAmountEditText widget.  Within this method, you can see how the methods getText() and setText() are used to access the contents of our widgets.  Since these widgets only store String values, we need to convert to and from double values to make calculations.  The getText() method returns an Editable object that represents the text that the widget contains.  To get a String from this we need to use its toString() method.  Also note the use of the NumberFormat class here to format our currency and percentage values in a locale-specific way.  We could have used String.format() instead, but this way our app will automatically adjust its number formatting for different countries.

Adding Event Handling

We’re almost there!  You’ll recall from learning Swing that an event occurs when a user interacts with a widget.  To deal with an event we need to associate the widget with an event listener object that implements a method to handle the event.  This works the same way with Android development.

First, we need to import the necessary interfaces.  An EditorAction event occurs when a user enters information into an EditText widget, and a Click event occurs when the user clicks on a Button widget.

Add the following imports to the code:

Next, add the following inner class to handle changes to our billAmountEditText widget:

This class implements the onEditorActionListener interface, which requires us to override the onEditorAction() method.  Android will call this method automatically when an event occurs.  If you have more than one EditText widget, you can use the first parameter (TextView v) to determine which widget triggered the event (EditText is a subclass of TextView).  The second parameter indicates what the user did in the EditText.  The constant IME_ACTION_DONE means that the user has finished updating the text (i.e., closed the soft keyboard).  In this case, we call our calculateAndDisplay() helper method to reflect the changes.  Returning false causes the soft keyboard to be hidden after the event; returning true will keep it open.

Now add the following inner class to handle Button events:

The onClick() method will be called when our decreaseButton or increaseButton widgets are pressed.  Because both buttons will share the same event listener object, we use the getId() method to determine which Button widget was clicked on and update the tipPercentage accordingly.  Again, the calculateAndDisplay() method is called to reflect the new tip amount.

Finally, we need to associate our widgets with these event handlers, just as we did with Swing.  To do this, add the following lines to the end of our onCreate() method.

Test the app again — if you’ve followed the instructions above carefully you should have a working, interactive app and a decent understanding of the Java code required to make it work!

You Try!

  1. Carefully read and follow the instructions above to build and test your own Tip Calculator app.
  2. Get creative! Experiment with the widget properties (e.g., text sizes, styles, colours, and padding etc..) to make your app look more attractive.
  3. Enhance the Tip Calculator app by adding a “Tax:” field between “Tip:” and “TOTAL:”. Assume the tax rate is 13% and will not change.  The tip and tax are calculated independently based on the bill amount.  For example, if the bill is $10.00, a 15% tip would be $1.50, the 13% tax would be $1.30, and the TOTAL should be $12.80.
  4. In U4-4 you implemented a coin/change calculator and a magic number guessing game using Swing.  Choose one of these Swing apps and redesign it as an Android app!