TABLE OF CONTENTS (HIDE)

Android Programming

Basics and User Interfaces

Introduction

Android is an Operating System for mobile devices developed by Google, which is built upon Linux kernel. Android competes with Sambian OS, Apple's iOS (for iPhone/iPad), RIM's Blackberry, Microsoft's Windows Phone (previously called Windows Mobile), and many other proprietary mobile OSes.

A Brief History
  • In 2005, Google acquired a start-up called Android Inc. and started to work on the Android platform, in particular the Dalvik Java Virtual Machine.
  • In 2007, a group of mobile handset producers and computing companies (including Google, Samsung, Motorola, Sony Ericsson, Intel, Toshiba, T-mobile, and Vodaphone) formed the Open Handset Alliance (OHA) to develop an open and non-proprietary mobile operating platform.
  • In September 2008, Google released Android SDK 1.0, and made the source code available under the Apache's open-source license. Android SDK 1.0 and 1.1 did not support soft keyboard and required physical keypad. Android 1.5 fixed this problem and including new features such as madia recording and playback; and widgets.
  • In October 2009, Google released Android SDK 2.0, which supports HTML 5, flash and many new features. In late 2010, Google released Android SDK 2.3, which supports the OpenGL ES 2.0, Near-Field (contact-less) Communications, and many improvements.
  • In March 2011, Google released Android SDK 3.0 (codenamed Honeycomb) targeting the tablets, with larger screen and more powerful processor.
  • Android 4.0 was released in October 2011.

The Android Platform

Dalvik Virtual Machine

Dalvik VM (DVM) was developed by Google, led by Dan Bornstein, so as to optimize the performance of Java applications on mobile devices with limited capablities (Dalvik is the name of a town in Iceland). DVM takes the traditional Java classes (".class") and combines them into one or more Dalvik Executable (".dex") files. By removing duplicate information among the Java classes, it reduces the resultant file size compared with the traditional JAR file. However, as a result, the DVM is not binary-compatible with Java Virtual Machine (JVM). You need to convert the .class into .dex.

Android 2.3 added a JIT (Just-in-time) compiler to improve the run-time performance. Android SDK uses XML file extensively. All the XML files are compiled into binary files to improve the performance.

Linux Kernel and Device Drivers

The Linux kernel is responsible for the OS functions, such as processor, memory, file, power management. The device drivers includes display, camera, keypad, flash memory, communications (GSM telephony, 3G, WiFi, bluetooth, Near-Field Contact-less communication), accessories (GPS, compass, accelerator), and etc.

Native C/C++ Libraries

The native C/C++ libraries include:

  • Google's Skia: for 2D graphics support (also used in Google's Chrome).
  • Khronos Group's OpenGL ES: for 3D graphics support.
  • WebKit: for broswer support (also used in Google's Chrome).
  • FreeType: for font support.
  • SSL (Secure Socket Layer): for secure communications.
  • SQLite: a lightweight relational database system.
  • PacketVideo's OpenCore: video/audio record and playback in various format.
  • Others.
Android Java API Packages

The API reference is available @ http://developer.android.com/reference/packages.html.

  • android.app:
  • android.view, android.widget:
  • andrioid.graphics, android.animation:
  • android.media, android.speech, android.telephony:
  • android.net:
  • android.bluetooth, android.location:
  • android.provider, android.content, android.database:
  • andriod.gesture:
  • android.sax:
  • android.security:
  • android.test, junit.framework, junit.runner:
  • android.text, android.util:
  • java.lang, java.io, java.nio, java.text, java.util
  • java.net, javax.net:
  • java.security, java.crypto:
  • java.sql, javax.sql:
  • javax.xml, org.json, org,w3c.dom, org.xml.sax, org.xmlpull:
  • org.apache.http:

Android Application Framework

Read: Android Developers Dev Guide "Application Fundamentals" (http://developer.android.com/guide/topics/fundamentals.html).

Revisit Hello-world

Let us revisit the Hello-world program, reproduced as follow:

package com.mytest;
   
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
   
public class HelloAndroid extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        TextView textView = new TextView(this); // Construct a TextView UI
        textView.setText("Hello, world!");      // Set text for TextView
        setContentView(textView);               // This Activity sets content to the TextView
    }
}
View

Views are UI components (such as button, label, text field) as well as containers, that could be used to build the user interface. In the hello-world, we use a view called TextView to display the message.

Android supports many of the core JDK packages, except graphics packages AWT and Swing. It provides its own 2D graphics supports, via views and widgets. It supports 3D graphics via OpenGL ES.

Activity

An Android application typically comprises several activities. An activity has a single screen, which usually composes of one of more views. An activity interacts with the user to do ONE (and only ONE) thing, such as viewing information, or editing data.

AndroidManifest.xml

Each application has a manifest, or application descriptor, to describe its contents, resources and behavior, such as the list of activities and services, intents and permissions. For example, the hello-world's manifest is as follow:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.mytest"
      android:versionCode="1"
      android:versionName="1.0" >
    <application android:icon="@drawable/icon" 
                 android:label="@string/app_name">
        <activity android:name=".HelloAndroid"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>
  • The root element <manifest> defines the XML name space and specifies the Java package name. It contains one <application> element.
  • The <application> element specifies the icon and label to be used in the mobile device's "apps" menu. It contains one ore more <activity> elements.
  • This application has one activity. The <activity> element declares its Java class name (.HelloAndroid where '.' is relative to the package com.mytest); and label (to be displayed as window title). It may contain <intent-filter> to declare the intent for this activity.

(The Android application descriptor file AndroidManifest.xml is similar to web application deployment descriptor web.xml in a JavaEE web application.)

Intent

An intent declares an intention to do something, such as launching an activity, broadcasting a message, starting a service, dialing or answering a phone call. An intent could be initiated by your application, or by the system to notify your application about a specific event (such as an incoming phone call).

For example, the <intent-filter> in the above manifest declares that this activity is the entry point (android.intent.action.MAIN) of the application when it is launched (android.intent.category.LAUNCHER). Recall that an application can contain one or more activities, and each activity performs one task.

Android Application Framework

An Android application is made up of components. An distinct feature of an Android application, comparing with other traditional application environments, is that it can make use of another application's components, without including the codes of the other application or linking to it. Instead, an application can simply start other application's component by instantiate Java objects for that component. An Android application does not have a single entry point (there is no main() method), but consists of components that can be instantiated and run as the need arises.

There are four type of application components:

  1. Activity: An activity has a single screen, which usually composes of one of more views. An activity interacts with the user to perform one task.
  2. Service: Background processes (similar to Windows' service or Unix's daemon), e.g., playing music.
  3. Broadcast Receiver: Receives and reacts to system messages, e.g., low battery life.
  4. Content Provider: Android defines a content provider mechanism for applications to share data without exposing the underlying implementation. Via content provider, your application can share data with other applications, or use data from another application (e.g., from SQLite Database).

Activity

As mentioned, an activity is a single, focused thing that the user can do (e.g., viewing information or entering data). It is usually presented in a single screen. It interacts with the user, through a visual UI composing of one or more views.

An Android application has one or more activities (multiple screens). One of the activities is marked as the starting activity, which can in turn start the next activity.

To create an activity, we extend the android.app.Activity class, and override some of its methods (in particular, onCreate() method) to provide our own implementation. A typical template of an Activity is as follows:

package ......;
   
import android.app.Activity;
import android.os.Bundle;
   
public class ..... extends Activity {
    /** Called back when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ......
        setContentView(......);  // Set the user interface on the screen
    }
}

The life cycle of an activity is managed via the following call-back methods, defined in the Activity base class:

  • onCreate(), onDestroy(): Called back when the Activity is created/destroyed.
  • onStart(), onStop(), onRestart(): Called back when the Activity is starting, stopping and re-starting.
  • onPause(), onResume(): Called when the Activity is paused/resume, can be used to release resources or initialize states.

Refer to Android API on Activity (http://developer.android.com/reference/android/app/Activity.html) for the life cycle's state diagram.

User Interfaces

Read:

Views & Layouts

An Activity interacts with the user, via a visual UI on a screen. The UI is placed on the Activity via the Activity.setContentView() method. In Android, the UI composes of View (UI components such as button, label and text field) and ViewGroup (layout) objects, organized in a single tree-structure.

A View is an interactive UI component, such as button and text field. It controls a rectangular area on the screen. It is responsible for drawing itself and handling events (such as clicking, entering texts). Android provides many ready-to-use Views such as TextView, EditText, Button, RadioButton, etc, in package android.widget. You can create your custom View by extending android.view.View.

A ViewGroup is an invisible container used to layout the View components. Android provides many ViewGroups such as LinearLayout, RelativeLayout, TableLayout and GridLayout. You can create your ViewGroup by extending from android.view.ViewGroup.

Views and ViewGroups are organized in a single tree structure called view-tree. You can create a view-tree either using programming codes or describing it in a XML layout file. XML layout is recommended as it separates the presentation view from the controlling logic, which provides modularity and flexibility in your program design. Once a view-tree is constructed, you can add the root of the view-tree to the Activity as the content view via Activity.setContentView() method.

Revise the "Hello-world in XML Layout", if necessary.

Example 1: Views (EditText, RadioButton, Button) and ViewGroup (LinearLayout)

Let's illustrate the view-tree with a simple example as illustrated.

The UI consists of a text field (EditText), two radio buttons (RadioButton) and a button (Button), arranged linearly in vertical orientation (LinearLayout).

First, create an Android project called "Counter", with target at "Android 2.2", application name of "Counter", package "com.mytest" and main activity "CounterActivity".

(You should set the target at the lowest possible level that supports your application requirements. This is because your codes will be able to run on the later versions, but not vice versa. Setting to lowest level will maximize the number of devices that your application can run on. These examples should be supported in Android 2.0, or even any version above 1.6. Also, you should test your codes on various AVDs of higher versions.)

res\layout\main.xml and res\values\strings.xml

Expand the project node, and replace the "res\layout\main.xml" with the following codes:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >
    <EditText 
        android:id="@+id/txtCountId"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        android:editable="false" />
    <RadioGroup
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content"
        android:orientation="horizontal" >
        <RadioButton
            android:id="@+id/radioUpId" 
            android:text="@string/radioUpLabel" 
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content" 
            android:checked="true" />
        <RadioButton
            android:id="@+id/radioDownId" 
            android:text="@string/radioDownLabel" 
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content" />
    </RadioGroup>
    <Button 
        android:id="@+id/btnCountId"
        android:text="@string/btnCountLabel" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" />
</LinearLayout>

This XML layout file describes a view-tree, composing of Views (UI components) and ViewGroups (layouts) objects. The root of this view-tree is a LinearLayout, which has 3 children: EditText, RadioGroup and Button. RadioGroup is also a layout ViewGroup which has two children of RadioButton.

Each object has its own set of properties (attributes). The common attributes are:

  • id: an integer used for referencing the object. Instead of hardcoding the integer, we use a special syntax @+id/idName, with a '+' sign to ask the Android SDK to generate a new ID resource. To reference an element, we use syntax @id/idName, without the '+' sign.
    For example, in the Button declaration, we generate a new id called btnCountId as follow:
    <Button android:id="@+id/btnCountId" ...... />
    
    Once the id is set up, we can use this id to reference the object and manipulate the object in our programming codes. For example, in our Activity's onCreate() method, we can retrieve a reference to the button (via method findViewById()), and attach an on-click event handler:
    public class CounterActivity extends Activity {
       
       /** Called when the activity is first created. */
       @Override
       public void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.main);
      
          // Retrieve a reference to the Button view by finding it by its id
          Button btnCount = (Button)findViewById(R.id.btnCountId);
          btnCount.setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View arg0) { ...... }
          });
        }
    }
    (This approach is very similar to JavaScript programming, which uses document.getElementById("idname") to retrieve an element, and process the element or attach an event handler such as onclick.)
  • layout_width and layout_height: specifying the rectangular area of the View or ViewGroup. It is recommended to use a relative measurement, such as FILL_PARENT (as big as its parent, renamed to MATCH_PARENT in API level 8) or WRAP_CONTENT (big enough to enclose its content). You can also provide an absolute measurement by specifying a floating-point number with a unit, e.g., 12.5px. The available measurement units are px (pixels), dp or dip (density-independent pixels), sp (scaled pixels based on preferred font size), in (inches), and mm (millimeters).
    In our example, the root LinearLayout fills the entire screen (FILL_PARENT in both width and height). The EditText displays across the screen (FILL_PARENT for width) with a height big enough to enclose its content (WRAP_CONTENT for height).
  • text: specifying an initial text for a text field, or a label for a button. Instead of hardcoding the text in the XML layout file, it is recommended to provide a string reference in the form of @string/stringName in the layout file, and place the actual text in "res\values\strings.xml". In this way, you could provide different strings for different locales (languages and countries) for internationalization (i18n) support.
    For this example, we used string references radioUpLabel and radioDownLabel (for RadioButton) and btnCountLabel (for Button).
    Next, replace "res\values\strings.xml" to provide the actual string texts, as follows:
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <string name="btnCountLabel">COUNT</string>
        <string name="radioUpLabel"  >Count Up</string>
        <string name="radioDownLabel">Count Down</string>
        <string name="app_name">Counter</string>
    </resources>
    Take note that the reference app_name keeps the application name (to be displayed in the device's apps menu) which we configured while creating the Eclipse project.
  • orientation="horizontal|vertical": For layouts such as LinearLayout and RadioGroup, you can specify whether to arrange its children in horizontal or vertical orientation. In our example, the LinearLayout uses vertical orientation, while RadioGroup uses horizontal.
  • others: There are many other attributes. Some attributes are applicable to a certain object only. For example, you can use checked="true" to set the initial state of a RadioButton; and editable="false" to make the EditText read-only.
CounterActivity.java

Let's complete our example by writing the main Activity class to process the button-clicks:

package com.mytest;
   
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RadioButton;
   
public class CounterActivity extends Activity {
   // References to UI views
   EditText txtCount;
   RadioButton radioUp;
   RadioButton radioDown;
   Button btnCount;
   
   int count = 0;    // Initial count
   
   /** Called when the activity is first created. */
   @Override
   public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);    // Set content view to XML layout
        
      // Retrieve references to UI views by their id in XML layout
      radioUp = (RadioButton)findViewById(R.id.radioUpId);
      radioDown = (RadioButton)findViewById(R.id.radioDownId);
      txtCount = (EditText)findViewById(R.id.txtCountId);
      txtCount.setText(String.valueOf(count));  // Set initial count
   
      btnCount = (Button)findViewById(R.id.btnCountId);
      // Process the button on-click event
      btnCount.setOnClickListener(new OnClickListener() {
         @Override
         public void onClick(View arg0) {
            if (radioUp.isChecked()) {          // Counting up
               count++;
            } else if (radioDown.isChecked()) { // Counting down
               count--;
            }
            txtCount.setText(String.valueOf(count));
         }
      });
   }
}

Now, you can run the application.

Dissecting CounterActivity.java

[TODO]

Generated AndroidManifest.xml

Each Android application has a manifest file (or application descriptor) named AndroidManifest.xml, in the project's root directory. It describes the application components. The manifest is generated automatically by the Eclipse ADT:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.mytest"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" 
                 android:label="@string/app_name">
        <activity android:name=".CounterActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

In our example,

  • The <manifest> element specifies the Java package name and program version. It contains one <application> element.
  • The <application> element specifies the icon and label used in mobile device's "apps" menu. It contains one ore more <activity> elements.
  • This application has one activity named CounterActivity. The <activity> element declares its program name (.CounterActivity where '.' is relative to the package com.mytest) and label (string reference app_name, where actual text in res\values\strings.xml). It may contain <intent-filter>.
  • The <intent-filter> declares that this activity is the entry point (intent.action.MAIN) of the application when it is launched (intent.category.LAUNCHER).
Generated R.java
/* AUTO-GENERATED FILE.  DO NOT MODIFY.
 * This class was automatically generated by the aapt tool from 
 * the resource data it found.  It should not be modified by hand.
 */
package com.mytest;
   
public final class R {
    public static final class attr {
    }
    public static final class drawable {
        public static final int icon=0x7f020000;
    }
    public static final class id {
        public static final int btnCountId=0x7f050003;
        public static final int radioDownId=0x7f050002;
        public static final int radioGroupId=0x7f050004;
        public static final int radioUpId=0x7f050001;
        public static final int txtCountId=0x7f050000;
    }
    public static final class layout {
        public static final int main=0x7f030000;
    }
    public static final class string {
        public static final int app_name=0x7f040003;
        public static final int btnCountLabel=0x7f040000;
        public static final int radioDownLabel=0x7f040002;
        public static final int radioUpLabel=0x7f040001;
    }
}

Eclipse ADT automatically generates a R.java (R for resources) to keep track and instantiate all the resources (icons, string, view and layout) used in the application. The resource IDs are kept in inner classes R.id, R.drawable, R.layout, R.string, which maps to the respective resource folders. For example, R.layout.main maps to res\layout\main.xml. R.string maps to res\values\strings.xml.

Example 2: Relative Layout

Let's modify our program to use RelativeLayout, instead of LinearLayout. In relative layout, the UI are arranged relative to each others.

res\layout\main_relative.xml

We shall use the same project (as the previous example). Create a XML layout file called main_relative.xml in res\layout folder (right-click on the res\layout node ⇒ new ⇒ file) as follows:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >
    <EditText 
        android:id="@+id/txtCountId" 
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        android:editable="false" 
        android:gravity="right" />
    <RadioGroup
        android:id="@+id/radioGroupId" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content"
        android:orientation="horizontal" 
        android:layout_below="@id/txtCountId" 
        android:layout_alignParentRight="true" >
        <RadioButton
            android:id="@+id/radioUpId" 
            android:text="@string/radioUpLabel" 
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content" 
            android:checked="true" />
        <RadioButton
            android:id="@+id/radioDownId" 
            android:text="@string/radioDownLabel" 
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content" />
    </RadioGroup>
    <Button 
        android:id="@+id/btnCountId"
        android:text="@string/btnCountLabel" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content"
        android:layout_below="@id/radioGroupId"
        android:layout_alignParentRight="true" />
</RelativeLayout>

We use the RelativeLayout as the root element. In relative layout, we need to assign an id to elements that would be used for reference. As mentioned, to create an id, we use a special syntax @+id/idName, with a '+' sign to ask the Eclipse ADT to generate an integer id. To reference an element, we use the syntax @id/idName.

In relative layout, we could use layout_below, layout_toLeftOf, layout_toRightOf, layout_alignParentRight, layout_alignTop, etc, (defined in android.widget.RelativeLayout.LayoutParams) to arrange a UI view relative to another view.

In this example, the RadioGroup is placed below the EditText and right-aligned with its parent RelativeLayout. The Button is placed below the RadioGroup, and also right-aligned with its parent RelativeLayout. In the EditText, the gravity="right" right-aligns the text.

CounterActivity.java

To use the new XML layout file, simply change the Activity.setContentView() as follows:

public void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.main_relative);  // Use res\layout\main_relative.xml
   ......
}
res\values\Strings.xml

No Change.

Next?

Study "Hello View" examples at http://developer.android.com/resources/tutorials/views/index.html for the pre-defined views and layouts in Android SDK.

  • LinearLayout: A ViewGroup that displays its View children in linear direction, either horizontally or vertically.
  • RelativeLayout: A ViewGroup that display its View children in relative position to each others or to the parent. e.g., below, align (top, left, right, bottom), margin (top, left, right, bottom).
  • TableLayout: A ViewGroup that display its View children in table of rows and columns.
  • GridLayout: A ViewGroup that display its View children in a 2D scrollable grid.
  • TabLayout: for organizing activities in separate tabs.
  • ListView: A ViewGroup that create a list of scrollable items.

Study the "Hello Localization" example at http://developer.android.com/resources/tutorials/localization/index.html on how to provide different strings for different locales (languages and countries).

Example 3: Simple Calculator

Create a project called CalculatorSimple, with target at "Android 2.2", application name of "Simple Calculator", package "com.mytest", and main activity "CalculatorActivity".

res\layout\main.xml

The UI consists of an EditText for displaying the result and 16 Buttons. We use TableLayout to layout the buttons in rows and columns as illustrated.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >
    <EditText 
        android:id="@+id/txtResultId" 
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        android:editable="false" 
        android:gravity="right" />
    <TableLayout
        android:id="@+id/tableId" 
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        android:layout_below="@id/txtResultId" >
        <TableRow> 
            <Button
                android:id="@+id/btnNum7Id" 
                android:text="7" 
                android:layout_width="fill_parent" 
                android:layout_height="wrap_content" 
                android:layout_weight="1" /> 
            <Button
                android:id="@+id/btnNum8Id" 
                android:text="8" 
                android:layout_width="fill_parent" 
                android:layout_height="wrap_content" 
                android:layout_weight="1" />
            <Button
                android:id="@+id/btnNum9Id" 
                android:text="9" 
                android:layout_width="fill_parent" 
                android:layout_height="wrap_content" 
                android:layout_weight="1" /> 
            <Button
                android:id="@+id/btnDivId" 
                android:text="÷" 
                android:layout_width="fill_parent" 
                android:layout_height="wrap_content" 
                android:layout_weight="1" />
        </TableRow>
        <TableRow> 
            <Button
                android:id="@+id/btnNum4Id" 
                android:text="4" 
                android:layout_width="fill_parent" 
                android:layout_height="wrap_content" 
                android:layout_weight="1" /> 
            <Button
                android:id="@+id/btnNum5Id" 
                android:text="5" 
                android:layout_width="fill_parent" 
                android:layout_height="wrap_content" 
                android:layout_weight="1" />
            <Button
                android:id="@+id/btnNum6Id" 
                android:text="6" 
                android:layout_width="fill_parent" 
                android:layout_height="wrap_content" 
                android:layout_weight="1" /> 
            <Button
                android:id="@+id/btnMulId" 
                android:text="×" 
                android:layout_width="fill_parent" 
                android:layout_height="wrap_content" 
                android:layout_weight="1" />
        </TableRow>
        <TableRow> 
            <Button
                android:id="@+id/btnNum1Id" 
                android:text="1" 
                android:layout_width="fill_parent" 
                android:layout_height="wrap_content" 
                android:layout_weight="1" /> 
            <Button
                android:id="@+id/btnNum2Id" 
                android:text="2" 
                android:layout_width="fill_parent" 
                android:layout_height="wrap_content" 
                android:layout_weight="1" /> 
            <Button
                android:id="@+id/btnNum3Id" 
                android:text="3" 
                android:layout_width="fill_parent" 
                android:layout_height="wrap_content" 
                android:layout_weight="1" /> 
            <Button
                android:id="@+id/btnSubId" 
                android:text="-" 
                android:layout_width="fill_parent" 
                android:layout_height="wrap_content" 
                android:layout_weight="1" /> 
        </TableRow>
        <TableRow> 
            <Button
                android:id="@+id/btnNum0Id" 
                android:text="0" 
                android:layout_width="fill_parent" 
                android:layout_height="wrap_content" 
                android:layout_weight="1" /> 
            <Button
                android:id="@+id/btnClearId" 
                android:text="C"
                android:layout_width="fill_parent" 
                android:layout_height="wrap_content" 
                android:layout_weight="1" /> 
            <Button
                android:id="@+id/btnEqualId" 
                android:text="="
                android:layout_width="fill_parent" 
                android:layout_height="wrap_content" 
                android:layout_weight="1" /> 
            <Button
                android:id="@+id/btnAddId" 
                android:text="+" 
                android:layout_width="fill_parent" 
                android:layout_height="wrap_content" 
                android:layout_weight="1" /> 
        </TableRow>
    </TableLayout>    
</RelativeLayout>
res\values\strings.xml

All strings, except app_name, are hardcoded in main.xml, as they are international symbols.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">Simple Calculator</string>
</resources>
CalculatorActivity.java
package com.mytest;
  
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
  
public class CalculatorActivity extends Activity implements OnClickListener {
  
   private EditText txtResult;  // Reference to EditText of result
   private int result = 0;      // Result of computation
   private String inStr = "0";  // Current input string
   // Previous operator: '+', '-', '*', '/', '=' or ' ' (no operator)
   private char lastOperator = ' ';
   
   /** Called when the activity is first created. */
   @Override
   public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);
      
      // Retrieve a reference to the EditText field for displaying the result.
      txtResult = (EditText)findViewById(R.id.txtResultId);
      txtResult.setText("0");
      
      // Register listener (this class) for all the buttons
      ((Button)findViewById(R.id.btnNum0Id)).setOnClickListener(this);
      ((Button)findViewById(R.id.btnNum1Id)).setOnClickListener(this);
      ((Button)findViewById(R.id.btnNum2Id)).setOnClickListener(this);
      ((Button)findViewById(R.id.btnNum3Id)).setOnClickListener(this);
      ((Button)findViewById(R.id.btnNum4Id)).setOnClickListener(this);
      ((Button)findViewById(R.id.btnNum5Id)).setOnClickListener(this);
      ((Button)findViewById(R.id.btnNum6Id)).setOnClickListener(this);
      ((Button)findViewById(R.id.btnNum7Id)).setOnClickListener(this);
      ((Button)findViewById(R.id.btnNum8Id)).setOnClickListener(this);
      ((Button)findViewById(R.id.btnNum9Id)).setOnClickListener(this);
      ((Button)findViewById(R.id.btnAddId)).setOnClickListener(this);
      ((Button)findViewById(R.id.btnSubId)).setOnClickListener(this);
      ((Button)findViewById(R.id.btnMulId)).setOnClickListener(this);
      ((Button)findViewById(R.id.btnDivId)).setOnClickListener(this);
      ((Button)findViewById(R.id.btnClearId)).setOnClickListener(this);
      ((Button)findViewById(R.id.btnEqualId)).setOnClickListener(this);
   }
  
   // On-click event handler for all the buttons
   @Override
   public void onClick(View view) {
      switch (view.getId()) {
         // Number buttons: '0' to '9'
         case R.id.btnNum0Id:
         case R.id.btnNum1Id:
         case R.id.btnNum2Id:
         case R.id.btnNum3Id:
         case R.id.btnNum4Id:
         case R.id.btnNum5Id:
         case R.id.btnNum6Id:
         case R.id.btnNum7Id:
         case R.id.btnNum8Id:
         case R.id.btnNum9Id:
            String inDigit = ((Button)view).getText().toString(); 
            if (inStr.equals("0")) {  
               inStr = inDigit;    // no leading zero
            } else {
               inStr += inDigit;   // accumulate input digit
            }
            txtResult.setText(inStr);
            // Clear buffer if last operator is '='
            if (lastOperator == '=') {
               result = 0;
               lastOperator = ' ';
            }
            break;
            
         // Operator buttons: '+', '-', '*', '/' and '='
         case R.id.btnAddId:
            compute();
            lastOperator = '+';
            break;
         case R.id.btnSubId:
            compute();
            lastOperator = '-';
            break;
         case R.id.btnMulId:
            compute();
            lastOperator = '*';
            break;
         case R.id.btnDivId:
            compute();
            lastOperator = '/';
            break;
         case R.id.btnEqualId:
            compute();
            lastOperator = '=';
            break;
  
         // Clear button
         case R.id.btnClearId:   
            result = 0;
            inStr = "0";
            lastOperator = ' ';
            txtResult.setText("0");
            break;
      }
   }
   
   // User pushes '+', '-', '*', '/' or '=' button.
   // Perform computation on the previous result and the current input number,
   // based on the previous operator.
   private void compute() {
      int inNum = Integer.parseInt(inStr);
      inStr = "0";
      if (lastOperator == ' ') {
         result = inNum;
      } else if (lastOperator == '+') {
         result += inNum;
      } else if (lastOperator == '-') {
         result -= inNum;
      } else if (lastOperator == '*') {
         result *= inNum;
      } else if (lastOperator == '/') {
         result /= inNum;
      } else if (lastOperator == '=') {
         // Keep the result for the next operation
      }
      txtResult.setText(String.valueOf(result));
   }
}
Dissecting CalculatorActivity.java

We register the same listener object (this object) to all the 16 Buttons. In the on-click event handler, we inspect the View object's id to dispatch the appropriate action. [TODO more]

Example 4

[TODO]

REFERENCES & RESOURCES