Newsreel

Loading...

Tuesday, September 20, 2011

Android Development Tutorial


Development with Android Gingerbread and Eclipse

This tutorial describes how to create Android applications with Eclipse. It is based on Eclipse 3.7 (Indigo), Java 1.6 and Android 2.3.3 (Gingerbread).


1. Android Development

1.1. Android Operation System

Android is an operating system based on Linux with a Java programming interface. It provides tools, e.g. a compiler, debugger and a device emulator as well as its own Java Virtual machine (Dalvik Virtual Machine - DVM). Android is created by the Open Handset Alliance which is lead by Google.
Android uses a special virtual machine, e.g. the Dalvik Virtual Machine. Dalvik uses special bytecode. Therefore you cannot run standard Java bytecode on Android. Android provides a tool "dx" which allows to convert Java Class files into "dex" (Dalvik Executable) files. Android applications are packed into an .apk (Android Package) file by the program "aapt" (Android Asset Packaging Tool) To simplify development Google provides the Android Development Tools (ADT) for Eclipse . The ADT performs automatically the conversion from class to dex files and creates the apk during deployment.
Android supports 2-D and 3-D graphics using the OpenGL libraries and supports data storage in a SQLite database.
Every Android applications runs in its own process and under its own userid which is generated automatically by the Android system during deployment. Therefore the application is isolated from other running applications and a misbehaving application cannot easily harm other Android applications.

1.2. Important Android components

An Android application consists out of the following parts:
  • Activity - Represents the presentation layer of an Android application, e.g. a screen which the user sees. An Android application can have several activities and it can be switched between them during runtime of the application.
  • Views - The User interface of an Activities is build with widgets classes which inherent from "android.view.View". The layout of the views is managed by "android.view.ViewGroups".
  • Services - perform background tasks without providing an UI. They can notify the user via the notification framework in Android.
  • Content Provider - provides data to applications, via a content provider your application can share data with other applications. Android contains a SQLite DB which can serve as data provider
  • Intents are asynchronous messages which allow the application to request functionality from other services or activities. An application can call directly a service or activity (explicit intent) or ask the Android system for registered services and applications for an intent (implicit intents). For example the application could ask via an intent for a contact application. Application register themself to an intent via an IntentFilter. Intents are a powerful concept as they allow to create loosely coupled applications.
  • Broadcast Receiver - receives system messages and implicit intents, can be used to react to changed conditions in the system. An application can register as a broadcast receiver for certain events and can be started if such an event occurs.

Other Android parts are Android Widgets or Live Folders and Live Wallpapers . Live Folders display any source of data on the homescreen without launching the corresponding application.

1.3. Security and permissions

Android defines certain permissions for certain tasks. For example if the application want to access the Internet it must define in its configuration file that it would like to use the related permission. During the installation of an Android application the user get a screen in which he needs to confirm the required permissions of the application.

1.4. AndroidManifest.xml

An Android application is described the file "AndroidManifest.xml". This file must declare all activities, services, broadcast receivers and content provider of the application. It must also contain the required permissions for the application. For example if the application requires network access it must be specified here. "AndroidManifest.xml" can be thought as the deployment descriptor for an Android application.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="de.vogella.android.temperature"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".Convert"
                  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>
    <uses-sdk android:minSdkVersion="9" />

</manifest> 
   

The "package" attribute defines the base package for the following Java elements. It also must be unique as the Android Marketplace only allows application for a specfic package once. Therefore a good habit is to use your reverse domain name as a package to avoid collisions with other developers.
"android:versionName" and "android:versionCode" specify the version of your application. "versionName" is what the user sees and can be any string. "versionCode" must be an integer and the Android Market uses this to determine if you provided a newer version to trigger the update on devices which have your application installed. You typically start with "1" and increase this value by one if you roll-out a new version of your application.
"activity" defines an activity in this example pointing to the class "de.vogella.android.temperature.Convert". For this class an intent filter is registered which defines that this activity is started once the application starts (action android:name="android.intent.action.MAIN"). The category definition (category android:name="android.intent.category.LAUNCHER" ) defines that this application is added to the application directory on the Android device. The @ values refer to resource files which contain the actual values. This makes it easy to provide different resources, e.g. strings, colors, icons, for different devices and makes it easy to translate applications.
The "uses-sdk" part of the "AndroidManifest.xml" defines the minimal SDK version your application is valid for. This will prevent your application being installed on devices with older SDK versions.

1.5. R.java, Resources and Assets

The directory "gen" in an Android project contains generated values. "R.java" is a generated class which contains references to resources of the "res" folder in the project. These resources are defined in the "res" directory and can be values, menus, layouts, icons or pictures or animations. For example a resource can be an image or an XML files which defines strings.
If you create a new resources, the corresponding reference is automatically created in "R.java". The references are static int values, the Android system provides methods to access the corresponding resource. For example to access a String with the reference id "R.string.yourString" use the method getString(R.string.yourString)); Please do not try to modify "R.java" manually.
While the directory"res" contains structured values which are known to the Android platform the directory "assets" can be used to store any kind of data. In Java you can access this data via the AssetsManager and the method getAssets().

1.6. Activities and Layouts

The user interface for Activities is defined via layouts. Layouts are at runtime instances of "android.view.ViewGroups". The layout defines the UI elements, their properties and their arragement. UI elements are based on the class "android.view.View". ViewGroup is a subclass of View A and a layout can contain UI components (Views) or other layouts (ViewGroups). You should not nestle ViewGroups to deeply as this has a negativ impact on performance.
A layout can be defined via Java code or via XML. You typically uses Java code to generate the layout if you don't know the content until runtime; for example if your layout depends on content which you read from the internet.
XML based layouts are defined via a resource file in the folder "/res/layout". This file specifies the view groups, views, their relationship and their attributes for a specific layout. If a UI element needs to be accessed via Java code you have to give the UI element an unique id via the "android:id" attribute. To assign a new id to an UI element use "@+id/yourvalue". By conversion this will create and assign a new id "yourvalue" to the corresponding UI element. In your Java code you can later access these UI elements via the method findViewById(R.id.yourvalue).
Defining layouts via XML is usually the preferred way as this separates the programming logic from the layout definition. It also allows to define different layouts for different devices. You can also mix both approaches.

1.7. Activities and Lifecyle

The operating system controls the life cycle of your application. At any time the Android system may stop or destroy your application, e.g. because of an incoming call. The Android system defines a life cycle for an activities via pre-defined methods. The most important methods are:
  • onSaveInstanceState() - called if the activity is stopped. Used to save data so that the activity can restore its states if re-started
  • onPause() - always called if the Activity ends, can be used to release ressource or save data
  • onResume() - called if the Activity is re-started, can be used to initiaze fields

The activity will also be restarted if a so called "configuration change" happens. A configuration change for examples happens if the user changes the orientation of the device (vertical or horizontal). The activity is in this case restarted to enable the Android platform to load different resources for these configuration, e.g. layouts for vertical or horizontal mode. In the emulator you can simulate the change of the orientation via CNTR+F11.
You can avoid a restart of your application for certain configuration changes via the configChanges attribute on your activity definition in your AndroidManifest.xml. The following activity will not be restarted in case of orientation changes or position of the physical keyboard (hidden / visible).

<activity android:name=".ProgressTestActivity"
     android:label="@string/app_name"
     android:configChanges="orientation|keyboardHidden|keyboard">
</activity>
   

1.8. Context

The class android.content.Context provides the connections to the Android system. It is the interface to global information about the application environment. Context also provides the method which allows to receive Android services, e.g. the Location Service . As Activities and Services extend the class "Context" you can directly access the context via "this".

2. Installation

The following assume that you have already Eclipse installed. For details please see Eclipse Tutorial .

2.1. Android SDK

Download the Android SDK from the Android homepage under Android SDK download . The download contains a zip file which you can extract to any place in your file system, e.g. I placed it under "c:\android-sdk-windows". Avoid using spaces in the path name otherwise you may experience problems later.

2.2. Eclipse

Use the Eclipse update manager to install all available plugins for the Android Development Tools (ADT) from the URL https://dl-ssl.google.com/android/eclipse/ .

2.3. Configuration

In Eclipse open the Preferences dialog via Windows -> Preferences. Select Android and enter the installation path of the Android SDK.

Setting up the Android SDK in the Eclipse Preferences

Select Window -> Android SDK and AVD Manager from the menu.

Starting ADV Manager

Select "Available packages" and open the "Third Party Add-ons". Select the Google API 10 (Android 2.3.4) version of the SDK. We are using the Google version as this includes also the Google Maps which we might want to use later at a certain point.

Install Android API

Press "Install selected" and confirm the license for all package. After the installation restart Eclipse.

2.4. Android Source Code

The following step is optional.
During Android development it is very useful to have the Android source code available as Android uses a lot of defaults.
Haris Peco maintains plugins which provides access to the Android Source code code. Use the Eclipse update manager to install two of his plugins. Update site: "http://adt-addons.googlecode.com/svn/trunk/source/com.android.ide.eclipse.source.update" and "http://adt-addons.googlecode.com/svn/trunk/binedit/com.android.ide.eclipse.binedit.update".
More details can be found on the project website .

3. Create an Android Emulator Device

The Android tools include an emulator. This emulator behaves like a real Android device in most cases and allow you to test your application without having a real device. You can emulate one or several devices with different configurations. Each configuration is defined via an "Android Virtual Device" (AVD).
To define an AVD press the device manager button, press "New" and enter the following.

AVD


New AVD


Settings for a new AVD

We will select the box "Enabled" for Snapshots. This will make the second start of the virtual device much faster.
At the end press the button "Create AVD".This will create the device and display it under the "Virtual devices". To test if your setup is correct, select your device and press "Start".
After (a long time) your device should be started.

Running AVD

4. Error handling

Things are not always working as they should be. Several users report that get the following errors:
  1. Project ... is missing required source folder: 'gen'
  2. The project could not be built until build path errors are resolved.
  3. Unable to open class file R.java.

To solve this error select from the menu Project -> Clean.
If you having problems with your own code you can use the LogCat viewer as described in LogCat Viewer .

5. Your first Android project

5.1. Create Project


Tip

This app is also available on the Android Marketplace. Search for "vogella" for find this example.

Select File -> New -> Other -> Android -> Android Project and create the Android project "de.vogella.android.temperature". Enter the following.

New Android Project Wizard

Press "Finish". This should create the following directory structure.

Android Project Structure

While "res" contains structured values which are known to the Android platform the directory "assets" can be used to store any kind of data. In Java you can access this data via the AssetsManager and the method getAssets().

5.2. Two faces of things

The Android SDK allows to define certain artifacts, e.g. strings and UI's, in two ways, via a rich editor and directly via XML. The following description tries to use the rich UI but for validation lists also the XML. You can switch between both things by clicking on the tab on the lower part of the screen. For example in the Package Explorer select "res/layout/main.xml".

ADT Resource Editor

5.3. Create attributes

Android allows you to create attributes for resources, e.g. for strings and / or colors. These attributes can be used in your UI definition via XML or in your Java source code.
Select the file "res/values/string.xml" and press "Add". Select "Color" and enter "myColor" as the name and "#3399CC" as the value.

Adding Android Attributes


Details for a String

Add also the following "String" attributes. String attributes allow to translate the application at a later point.


Table 1. String Attributes
NameValue
myClickHandlermyClickHandler
celsiusto Celsius
fahrenheitto Fahrenheit
calcCalculate

Switch to the XML representation and validate the values.

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <string name="hello">Hello World, Convert!</string>
 <string name="app_name">Temperature Converter</string>
 <color name="myColor">#3399CC</color>
 <string name="myClickHandler">myClickHandler</string>
 <string name="celsius">to Celsius</string>
 <string name="fahrenheit">to Fahrenheit</string>
 <string name="calc">Calculate</string>
</resources>
   

5.4. Add UI Elements

Select "res/layout/main.xml" and open the Android editor via a double-click. This editor allows you to create the UI via drag and drop or via the XML source code. You can switch between both representations via the tabs at the bottom of the editor. For changing the postion and grouping elements you can use the outline view.
The following shows a screenshot of the Palette view from which you can drag and drop new UI elements into your layout. Please note that the "Palette" view changes frequently so your view might be a bit different.

Palette for the Android Layout Editor

Right-click on the text object “Hello World, Hello!” in the layout. Select Delete on the popup menu to remove the text object. Then, from the “Palette” view, select Text Fields and locate “Plain Text”. Drag this onto the layout to create a text input field. All object types in the section "Text Fields” derive from the class "EditText", they just specify via an additional attribute which text type can be used.
Now select the Palette section “Form Widgets” and drag a “RadioGroup” object onto the layout. The number of radio buttons added to the radio button group depends on your version of Eclipse. Make sure there are two radio buttons by deleting or adding radio buttons to the group.
From the Palette section Form Widgets, drag a Button object onto the layout.
The result should look like the following and the corresponding XML is listed below. Make sure that your code is the same as listed below.

Current layout of main.xml

Switch to "main.xml" and verify that your XML looks like the following.

<?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:layout_height="wrap_content" android:id="@+id/editText1"
  android:layout_width="match_parent" android:text="EditText"></EditText>
 <RadioGroup android:layout_height="wrap_content" android:id="@+id/radioGroup1"
  android:layout_width="match_parent">
  <RadioButton android:text="RadioButton"
   android:layout_width="wrap_content" android:id="@+id/radio0"
   android:layout_height="wrap_content" android:checked="true"></RadioButton>
  <RadioButton android:text="RadioButton"
   android:layout_width="wrap_content" android:id="@+id/radio1"
   android:layout_height="wrap_content"></RadioButton>
 </RadioGroup>
 <Button android:text="Button" android:id="@+id/button1"
  android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
</LinearLayout>

   

5.5. Edit UI properties

If you select a UI element you can change its properties via the properties view. Most of the properties can also be changed via the right mouse menu. Select the EditText field, right mouse click on it, select Properties-> Text and delete the content. This means no text will be initially shown in the text field.

How to change properties of UI elements via the right mouse click


Remove the default text of the EditText field

Assign the "celsius" string attribute to your "text" property of the first radio button and "fahrenheit" to the second.

Change the text property of the radio button


Selection of the right text from the pre-defined string values

From now on I assume you are able to use the properties menu on the UI elements. Set the property "Checked" to true for the first RadioButton. Assign "calc" to the text property of your button and assign "myClickHandler" to the "onClick" property. Set the "Input type" property to "numberSigned" and "numberDecimal" on your EditText.
Right-click on the view in Graphical Layout mode, then select “Properties”/”Background...” from the popup menu. Select “Color” and then “myColor” in the list.

New look of the layout after the changes

Switch to the "main.xml" tab and verify that the XML is correctly maintained.

<?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" android:background="@color/myColor">
 <EditText android:layout_height="wrap_content" android:id="@+id/editText1"
  android:layout_width="match_parent" android:inputType="numberDecimal|numberSigned"></EditText>
 <RadioGroup android:layout_height="wrap_content" android:id="@+id/radioGroup1"
  android:layout_width="match_parent">
  <RadioButton android:layout_width="wrap_content"
   android:id="@+id/radio0" android:layout_height="wrap_content"
   android:text="@string/celsius" android:checked="true"></RadioButton>
  <RadioButton android:layout_width="wrap_content"
   android:id="@+id/radio1" android:layout_height="wrap_content"
   android:text="@string/fahrenheit"></RadioButton>
 </RadioGroup>
 <Button android:id="@+id/button1" android:layout_width="wrap_content"
  android:layout_height="wrap_content" android:text="@string/calc"
  android:onClick="myClickHandler"></Button>
</LinearLayout>

   

5.6. Code your application

Change your code in "Convert.java" to the following. Note that the "myClickHandler" will be called based on the "On Click" property of your button.

package de.vogella.android.temperature;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.Toast;

public class Convert extends Activity {
 private EditText text;

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  text = (EditText) findViewById(R.id.editText1);

 }

 // This method is called at button click because we assigned the name to the
 // "On Click property" of the button
 public void myClickHandler(View view) {
  switch (view.getId()) {
  case R.id.button1:
   RadioButton celsiusButton = (RadioButton) findViewById(R.id.radio0);
   RadioButton fahrenheitButton = (RadioButton) findViewById(R.id.radio1);
   if (text.getText().length() == 0) {
    Toast.makeText(this, "Please enter a valid number",
      Toast.LENGTH_LONG).show();
    return;
   }

   float inputValue = Float.parseFloat(text.getText().toString());
   if (celsiusButton.isChecked()) {
    text.setText(String
      .valueOf(convertFahrenheitToCelsius(inputValue)));
    celsiusButton.setChecked(false);
    fahrenheitButton.setChecked(true);
   } else {
    text.setText(String
      .valueOf(convertCelsiusToFahrenheit(inputValue)));
    fahrenheitButton.setChecked(false);
    celsiusButton.setChecked(true);
   }
   break;
  }
 }

 // Converts to celsius
 private float convertFahrenheitToCelsius(float fahrenheit) {
  return ((fahrenheit - 32) * 5 / 9);
 }

 // Converts to fahrenheit
 private float convertCelsiusToFahrenheit(float celsius) {
  return ((celsius * 9) / 5) + 32;
 }
}

   

5.7. Start Project

To start the Android Application, select your project, right click on it, Run-As-> Android Application Be patient, the emulator starts up very slow. You should get the following result.

The running application in the emulator

Type in a number, select your conversion and press the button. The result should be displayed and the other option should get selected.

5.8. Using the home menu

If you press the Home button you can also select your application.

How to select your application from the Android home menu


Selecting the application from the application choiser

No comments:

Post a Comment