Using Oxygene for Java to Develop for Android devices - Intro

Brian Long Consultancy & Training Services Ltd.
January 2012

Page selection: Previous  Next

Oxygene for Java

Android architecture overview

To get an understanding of how a simple Android applications works we’ll take a generalised overview of its architecture.

Application building blocks

An Android application is made up of various building blocks, each of which is designed to fulfil a specific type of goal. These are activities, services, broadcast receivers and content providers:

Applications have as many or as few of these components as befit the application’s requirements. The simplest application has just one activity.

An application does not have to implement all the above components it needs – it can make use of, say, activities and content providers from other applications that have been installed or from the basic Android system. A simple example would be browsing to a web site URL. There’s no real need to implement an activity that can display a web page, as your Android device will already have one (the built in browser app). You can invoke that existing activity instead.

In the project the class containing the code inherits from Android.App.Activity and so the application contains one activity component.

These application components can communicate in a few ways but the pervading communication mechanism is Android.Content.Intent. An intent can be used to start an activity, communicate with a service or be sent to an interested broadcast receiver. Since applications can make use of external components it follows that intents operate between applications. An intent represents a form of late (or run-time) binding between application components; it’s a type of structured message.

An explicit intent knows the application component it is to work with – it has the class name or type. An implicit intent does not; it just knows what you want to do and tries to find a component to satisfy that requirement.

Android manifest

Because an application is a collection of these potentially autonomous components, how does Android know what to do when an application is started? Moreover, how does Android know what components are implemented by the application so it can access them? Well, in the Android world the Android manifest file, AndroidManifest.xml, answers these and other questions.

The manifest file can contain lots of information to help the Android OS work well with your application. It allows you to describe your application components, identify what component will start when the application is launched by Android, specify any permissions required by the application, identify the minimum Android platform required, define what any published broadcast receivers can respond to, identify the application icon, specify a default application theme and much more besides.

Every Android project has an Android manifest file, which is stored in the Properties project subfolder, called Properties\AndroidManifest.xml. The manifest from the project we've generated looks something like this:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3.                 package="org.me.androidapplication1">
  4.   <!-- the android:debuggable="true" attribute is overwritten by the compiler when the debug info option is set -->
  5.   <application android:persistent="true"
  6.        android:label="@string/app_name"
  7.        android:icon="@drawable/icon"
  8.        android:debuggable="true">
  9.     <activity android:label="@string/app_name" android:name="org.me.androidapplication1.MainActivity">
  10.       <intent-filter>
  11.         <action android:name="android.intent.action.MAIN" />
  12.         <category android:name="android.intent.category.LAUNCHER" />
  13.       </intent-filter>
  14.     </activity>
  15.   </application>
  16.   <uses-sdk android:minSdkVersion="4" />
  17. </manifest>

In among this smattering of XML attributes, noteworthy things include:

Several of the attributes mentioned above refer to string or drawable resources and we'll see more about this syntax later.

Application lifecycle

It is important to be aware of how the Android OS manages the components in an application, because under certain low-memory circumstances, they can be unilaterally terminated. Since the sample application only has an activity in it we’ll look at the lifecycle of the Activity class. At each of the various milestones of the activity lifecycle a virtual method executes, thereby allowing you to override the method and run custom code at that point.

The entire lifetime of an activity goes from its creation, where onCreate(Bundle) is called, to its destruction, marked by onDestroy(). So basic initialisation and loading of the UI (via the assignment to ContentView as per the earlier code snippet) should occur in onCreate(Bundle) and general cleanup in onDestroy().

To mark its display on the screen onStart() is called, and the activity is now considered paused. When no longer visible onStop() is called and it is considered stopped. If it becomes visible again onRestart() is executed before onStart() gets another look-in.

After becoming visible the activity will be brought to the foreground (given focus), as indicated by onResume(). The activity is now considered active or running. When something knocks it out of the foreground (another activity coming to the foreground) onPause() runs, and it is considered paused once more. If it comes to the foreground again, this pair starts its cycle again. If it ends up being terminated, it goes through onStop() and onDestroy().

So, when an activity is started, onCreate(Bundle), onStart() and onResume() are called to bring it to the foreground. When something else comes to the foreground onPause() runs and there are potentially several onResume()/onPause() loops. When it leaves the screen the activity’s onStop() runs. If brought back to the foreground we have onRestart(), onStart() and onResume(). Eventually after onStop() you will get onDestroy().

Having got the idea of that it is important to remember that a phone is not a memory-rich arena and sometimes memory comes under pressure. At such times the Android OS has the opportunity to kill off activities that are not in the foreground. Typically this will involve killing activities that have executed onStop() and are waiting off-screen. However given enough extreme memory pressure Android will also kill off activities that are still visible but not foreground, such as activities sitting behind a dialog, i.e. those whose onPause() has run (although this is no longer true in Honeycomb, Android 3.0).

If your activity gets killed through memory pressure it will allow you to save state by running onSaveInstanceState(Bundle) just before the termination. You don’t need to worry about the controls (or widgets as they're called in Android) as their state is automatically saved and later restored, but you can save any other state data in the Bundle object passed to this routine. Whenever the activity is next invoked state can be restored from the Bundle object passed to onRestoreInstanceState(Bundle), which will be called after onStart() and before onResume(). Alternatively you can just use the Bundle object passed to onCreate(Bundle).

In the case of services the lifetime is simpler than for activities as there is no UI to be displayed and hidden. However, we’ll not worry about the specifics for services in this article.

In a simple case where there is no special state that requires saving and no UI-specific code that needs to execute when the activity is shown and hidden, or brought to the foreground and sent to the background, then you just need to load your UI in the onCreate(Bundle) and do any other setup.

When an activity is running, normal device behaviour when pressing the Home button is for the activity to be sent to the background, so onPause() and onStop() execute. If you switch back to the activity with a long press on Home or by pressing a shortcut to the application then the activity is resumed, thereby calling onRestart(), onStart() and onResume().

However if you press Back on an activity, it is (by default) killed off, so onPause(), onStop() and onDestroy() get called. You can alter this default behaviour by overriding the onBackPressed() virtual method. An activity can terminate itself by calling finish().

On a phone where hitting the power button enables the soft lock and turns of the display, this pauses the activity so onPause() is called immediately.

Application resources

We need to take a look at how the Android eco-system deals with resources, from UI definitions to text strings to icons. These can all be externalised from the code into a res subfolder within the Android project folder. Externalising resources allows you to readily support different configurations available on various Android devices, which, for example, run at different resolutions and/or with different screen densities. In the case of text strings, externalising these facilitates localising them to additional languages in a fairly straightforward manner.

Within the res folder are a varying number of additional subfolders containing different types of resources. The sample project has these resource subfolders:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <resources>
  3.   <string name="app_name">org.me.androidapplication1</string>
  4.   <string name="my_button_text">Click Me!</string>
  5.   <string name="my_button_text_2">%1$d clicks!</string>
  6. </resources>

Android supports other kinds of resources that have their own subfolder names. You can read up on this at http://d.android.com/guide/topics/resources/providing-resources.html.

Note: the files and folders within the res folder hierarchy must all have lower case names, a restriction imposed by the Android tool that processes the resources.

Note: The resource directory hierarchy defaults to being a project subfolder called res but this can be updated in the project options on the Android property sheet.

Accessing resources from code

All these resources need to be accessible from the code, and the R class helps achieve this. As you add resources into the res directory tree, a post-build operation updates the to contain various nested classes with their own members that map onto each resource. This R class is not found in a source file in the project as it is auto-generated during the build process. On the subject of this post-build auto-generated R class:

The sample project has an R class looking like this (although this one has been slightly edited for brevity, such as having default constructors and comments omitted):

  1. type
  2.   R = public sealed class
  3.   end;
  4.   attr nested in R = public static class
  5.   end;
  6.   drawable nested in R = public static class
  7.   public
  8.     const icon: Integer = $7f020000;
  9.   end;
  10.   id nested in R = public static class
  11.   public
  12.     const MyButton: Integer = $7f050000;
  13.   end;
  14.   layout nested in R = public static class
  15.   public
  16.     const main: Integer = $7f030000;
  17.   end;
  18.   string nested in R = public static class
  19.   public
  20.     const app_name: Integer = $7f040000;
  21.     const my_button_text: Integer = $7f040001;
  22.     const my_button_text_2: Integer = $7f040002;
  23.   end;

You can see here that the icon image, the main activity layout resource, a button id and three strings each have integer identifiers defined. Every time you build your project this file is updated to account for any new resources you may have added.

In the sample project, the UI is loaded up with a call to:

  ContentView := R.layout.main;

This references the main.xml UI layout resource via its integer resource identifier and assigns that to the activity's ContentView property (though see below for more on properties in Java and in Oxygene for Java).

Also in the activity's onCreate() method:

  var myButton: Button := Button(findViewById(R.id.MyButton));

This identifies a button widget via its id and asks the activity to locate the widget for the button using this id. The resultant View is typecast to a Button and assigned to a local variable. We'll see later how the button id was defined.

Finally, in the button event handler we had:

  (v as Button).Text := WideString.format(String[R.string.my_button_text_2], Count);

This uses the id of one of the string resources and builds up a formatted string from it.

Note: Widgets defined in Android layout files do not have variables automatically declared in the source code. For any widgets you need to access in code you need to set up variables and assign them values in this manner.

Accessing resources from XML

The resources also need to be accessible from XML files, such as the Android manifest file and layout files, or other resource files. The general form of this was seen in the Android manifest file above: "@resource_type/resource_id", for example:

"@string/app_name"
"@drawable/icon"

Java and properties

In the sample project code you can see the activity's main layout being assigned with the statement:

  ContentView := R.layout.main;

However if you were to search for this ContentView property in the Android SDK documentation you wouldn't find it. This is because Java does not support properties as a language feature.

Properties are a way of allowing a method that reads a value and a method that writes a value (both with optional side effects) to be treated like a singular data item (with optional side effects), simplifying two methods into one property. A property is like a data field with side effects and can optionally be read-only or write-only by not having a setter method or getter method respectively in its definition.

In Java there are no properties, just the getter and setter methods. In the case of an activity's layout, the available functionality is in fact a setter method (actually a set of three overloaded methods) called setContentView(), and of course these can be found in the documentation.

When Oxygene sees a setFoo() or getFoo() method in a referenced library, it immediately offers a property as if it were defined in terms of those getFoo()/setFoo() methods. You then have the option of using the property (as in the code in the sample project) as we would normally do in Delphi or C#, although you can still use the original methods if you wish.

Java and events

Java events are a little different to events that Delphi and .NET programmers may be familiar with. Indeed if you look at the sample project code you'll see an event handler being set up for the activity's button and it uses syntax that was added to support the Java way of dealing with events:

myButton.OnClickListener := new interface View.OnClickListener(OnClick := @ButtonOnClick);

In the world of Java events are managed with interfaces. An interface, often with a single method, is defined for the purpose of handling some event of some object. In the case of a button, its click event is managed with the View.OnClickListener interface and its OnClick() method. To handle the event you need to assign to the event property (OnClickListener in the case of a button click event, although this is an implied property and at the Java level we are really dealing with the setOnClickListener() method) an object that implements the interface.

One option would be to implement the required interface method in your activity class and assign self to the event property. This would work fine for one button, but of course to handle the clcick event of multiple buttons you'd quickly come unstuck as the activity can only implement a given interface once.

You could also consider implementing the interface in a different dedicated class for each button, but that would quickly become unwieldy. However a new shortcut syntax in Oxygene 5 essentially does that very job, at the same time allowing you to use a local method (or anonymous method or lambda expression) as the implementation of the interface method. This inline interface implementation syntax uses the keywords new interface to create a new object implementing the specified interface and then takes instruction as to how to implement each interface method. You can read more on this subject in my article about inline interface implementation.

In the snippet above the syntax creates an object implementing View.OnClickListener and specifies that the OnClick method is to be implemented by the activity's ButtonOnClick method. You can equally use an anonymous method here or a lambda expression. If the interface has more than one method you can use a comma-separated list to stipulate what to do for each method of interest. Any methods not listed will be given empty stub implementations.

In the case above the interface only has one method. Because of this we could simplify the statement using a permitted abbreviation and instead write:

myButton.OnClickListener := @ButtonOnClick;

Alternative resources

As stated above one of the prime reasons to externalise all the resources into the res folder tree is to support multiple configurations and multiple languages. This is enabled by using additional directories with suffixes formed by one or more instances of a hyphen (or dash, or minus sign) followed by a configuration qualifier.

There are config qualifiers for various configuration aspects, such as screen density, screen size, screen aspect, screen orientation and so forth. The resource directories without a suffix are the default resources. The ones with config qualifiers provide alternate resources for certain configurations on various devices.

Take, for example, the icon in the sample project. We saw earlier that in fact there are three icons supplied in directories that all basically a drawable directory, but with config qualifiers applied for hdpi, mdpi and ldpi screens. According to the Android UI guidelines, application launcher icons should be 72x72 pixels on High Density (hdpi) screens, 48x48 pixels on Medium Density (mdpi) screens and 36x36 on Low Density (ldpi) screens. The three default drawable directories provide application icons of these dimensions for these three screen densities using config-specific drawable directories.

The 36x36 ldpi default application icon looks like this: ldpi application icon

The 48x48 mdpi default application icon looks like this: mdpi application icon

The 72x72 hdpi default application icon looks like this: hdpi application icon

In the case of a resource directory for localised strings, the config qualifier specifies a language (ISO 639-1 language code) optionally followed by a hyphen, an r and a region (ISO 3166-1-alpha-2 region code), for example fr (French) or fr-rCA (French Canadian). The localised version of strings.xml can have as many or as few of the strings translated as is necessary. Android will always fall back on the default string if a translation is missing.

More information on providing alternative resources can be found in the Android SDK documentation at http://developer.android.com/guide/topics/resources/providing-resources.html#AlternativeResources.

UI layout files

The user interface of the sample project is defined in the file res\layout\main.xml, which looks like this:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3.    android:orientation="vertical"
  4.    android:layout_width="fill_parent"
  5.    android:layout_height="fill_parent"
  6.    android:gravity="center_vertical">
  7.  
  8.   <LinearLayout
  9.      android:orientation="horizontal"
  10.      android:layout_width="fill_parent"
  11.      android:layout_height="wrap_content"
  12.      android:gravity="center_horizontal">
  13.    
  14.     <Button
  15.        android:id="@+id/MyButton"
  16.        android:text="@string/my_button_text"
  17.        android:layout_width="wrap_content"
  18.        android:layout_height="wrap_content"></Button>
  19.    
  20.   </LinearLayout>
  21.  
  22. </LinearLayout>

When working with Oxygene for Java there is no visual UI designer; user interface layout is achieved by coding up XML files like the one above. When writing one of these files you will likely need to refer to the Android documentation to identify which attributes are permitted where, while getting used to it. However it is still a trial and error process, as you cannot see the effect of your layout until you run the application on a device or emulator.

Android programmers using Java and Eclipse do get a bit of a nod in the direction of a UI designer, but it’s not really much to be jealous of. Having talked to a Google representative, my understanding is that better UI design tools ought to be forthcoming now that they realise what a demand there is for them.

All that said there are UI designers out there. For example, DroidDraw from http://droiddraw.org is a free UI design tool that runs as a Java applet in the browser, although standalone executable versions are also available. You may find it useful, though it takes some getting used to. Be sure to follow the tutorials to learn how to use it.

Sticking with the raw manual creation strategy for the time being, let’s take a look at the layout file above.

Android UIs are hierarchical collections of Android.Views.View descendants, which typically reside in the Android.Widget namespace. In the case here there are two widgets: a layout widget and a control widget. There are various layout widgets including LinearLayout, RelativeLayout, AbsoluteLayout, FrameLayout and TableLayout. These have differing ways of organising the control widgets you place in them.

The sample layout uses a linear layout widget with a vertical orientation, so each control added will be placed below the previous one. Each widget needs a width and height specification. fill_parent is descriptive enough, but you can also use wrap_content to make it as large as is needed based on the controls or content within.

The only control (or widget) in the linear layout is a Button, set to be as wide as the screen (well, actually as wide as its parent, which was set to be as wide as the screen, given the linear layout was the top level view and also set to be as wide as its parent). The button’s text is set using the syntax for reading a string resource from the values\strings.xml file.

That leaves the id attribute. This uses a slightly different syntax to define a new identifier. MyButton does not exist until this id attribute definition, and the + sign in the value tells Android to make a new resource ID, which will be added into the R class. Indeed if you look back at this project’s R class you will see the MyButton ID defined in the Id nested class. This newly defined ID can be referred to elsewhere in the layout. For example if we were using a RelativeLayout instead of a LinearLayout, another widget could indicate it is to the right of MyButton using an attribute such as:

android:layout_toRightOf="@id/MyButton"

Additionally, the code can access the widget by passing the ID to findViewById(). The code in the sample project does this to get a reference to the button so that it can set up the Click event handler and update the button’s Text property when the button gets clicked.

So that concludes the look through the simple template Android app project, looking at the application lifecycle, the way resources are managed, how the UI is built and how the code access the UI.

Conclusion

This article has shown how Oxygene for Java facilitates utilization of existing Object Pascal programming ability to start building applications for Android devices in a very capable manner, providing a convenient means of starting to write Android apps without having to learn an entirely new programming language and development environment.

Of course, an understanding of the Android libraries needs to be built up in order to do the job well, but working with a language you are familiar with helps ease the transition to a new target platform.

Technical Resources

The Android documentation site is at http://developer.android.com (or the shorter URL of http://d.android.com).

The Android SDK documentation is at http://d.android.com/reference.

The Android UI Guidelines are at http://d.android.com/guide/practices/ui_guidelines.

Comments

If you wish to make any comments on this article, your best options are to comment on the blog post that announced it, use the Contact Me form or email me at .

If you find this article useful please consider making a Paypal donation. It will be appreciated however big or small it might be and will encourage Brian to continue researching and writing about technically interesting topics in the future.

About the author

Brian Long has spent the last 1.6 decades as a trainer, trouble-shooter and mentor focusing on the Delphi, Oxygene, C# and C++ languages, and the Win32, .NET and Mono platforms, recently adding iOS and Android onto the list. In his spare time, when not exploring the Chiltern Hills on his mountain-bike or pounding the pavement in his running shoes, Brian has been re-discovering and re-enjoying the idiosyncrasies and peccadilloes of Unix-based operating systems. Besides writing a Pascal problem-solving book in the mid-90s he has contributed chapters to several books, written countless magazine articles, spoken at many international developer conferences and acted as occasional Technical Editor for Sybex. Brian has a number of online articles that can be found at http://blong.com and a blog at http://blog.blong.com.

© 2012 Brian Long Consulting and Training Services Ltd. All Rights Reserved.


Go back to the top of this page

Go back to start of this article

Previous page

Next page