dmathieu - Getting started in android programming

Getting started in android programming

Tuesday, 17 August 2010 in Development Articles by Damien Mathieu Creative Commons License

For some weeks now, I’ve been having fun with java on android. In this article, we’re gonna see the basics of android application programming with a sample test application : translator.

What this application does if very simple. You enter the input language, the output and the string you wish to translate. Using Google Translate, the application will translate that string.

Installing the SDK

In order to be able to easily test our application, we’re gonna use the Android SDK, allowing us to simulate a cellphone on our computer.

You can download the SDK from the android’s official documentation depending of your operating system.

Generate the project

Because we don’t use Eclipse, we lose a lot of shortcuts provided by the IDE. But not using it is a choice. You can use the editor of your choice !

We’re first gonna start a new project. Android offers a console command for this : android create project

android create project \
    -t <target_ID> \
    -n <your_project_name> \
    -p /path/to/your/project \
    -a <your_activity_name> \
    -k <your_package_namespace>

Several options are required.

  • -t target : It is the version of the android platform we’re going to use (here, Android 2.1). To get a list of all the available platformes, you can use android list targets.
  • -name : The name you wish to give to your project.
  • -p path : The directory in which your project will be created.
  • -a activity : The name of the default window which will be opened when we’ll launch the application.
  • -k package : The name of the package which will be created. It must follow the naming convention for packages in java.

Let’s create our new project which we well name “Translator”.

android create project \
    -t 1 \
    -n Main \
    -p ~/projects/translator \
    -a Translator \
    -k com.android.translator

Pure Java : translate a string with Google Translate

hello world For this application, we’re going to use an open source library allowing us to make calls to Google Translate : Google API Translate Java. You must include this library in the project we’ve just created. Download it on Google Code (the .jar file) and put in the folder /libs of your project.

 

We’re gonna write an abstraction class for this library right now.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.android.translator;
import com.google.api.translate.Language;
import com.google.api.translate.Translate;

public class Translator {
    /*
     * Takes the string to translate and does the work
     */
    public static String translate(String text, Language lang_from, Language lang_to) throws Exception {
        Translate.setHttpReferrer("http//www.dmathieu.com");
        String translatedText = Translate.execute(text, lang_from, lang_to);
        return translatedText;
    }
}

What are we doing ?

1
2
3
package com.android.translator;
import com.google.api.translate.Language;
import com.google.api.translate.Translate;

We define the name of the current package and include the library previously downloaded, which will make the liaison with Google Translate.

1
Translate.setHttpReferrer("http//www.dmathieu.com");

The Google Translate API requires us to provide a referer, for statistic reasons. You can provide any uri you want here.

1
String translatedText = Translate.execute(text, lang_from, lang_to);

We get the translated string and we return it.

Then we call Translator.translate in order to translate one string from one language to an other.

1
Translator.translate("Hello World", Language.ENGLISH,  Language.FRENCH);

Create a Translator.java file in the folder src/com/android/translator and put this code in it.

And … That’s all for now. We’re now going to see how to create the application’s interface.

Create the Android interface

We’re now going to create our application’s interface, which will have two select boxes, one text field, one button and our translated string. Any application’s interface is to be programmed in XML.

Here’s what we have for the screen above, located in the file res/layout/main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?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:layout_weight="1">

    <Spinner
        android:id="@+id/languages_from"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:prompt="@string/from_languages_prompt" />

    <Spinner
        android:id="@+id/languages_to"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:prompt="@string/to_languages_prompt" />

    <EditText
        android:id="@+id/text_to_translate"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="@android:drawable/editbox_background"
        android:prompt="@string/text_to_translate" />

    <Button
        android:id="@+id/translate_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:text="@string/translate_button" />

    <TextView
        android:id="@+id/translated_text"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

What happens here ?

1
2
3
4
5
6
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_weight="1">
</LinearLayout>

We define the current window. LinearLayout allows us to define a window with all the elements which will be placed ones after the other.

There are several layout types allowing you to dispose the elements as you wich :

  • AbsoluteLayout : Allows you to place the elements by specifying their x/y coordinates.
  • FrameLayout : Allows you to place one and only one element. If there are several ones, only the last one will be displayed.
  • RelativeLayout : A layout in which everl elements are located one after the other.
  • TableLayout : A layout allowing you to place it’s childs in lines or columns.

Then inside this layout, we have several elements.

1
2
3
4
5
<Spinner
    android:id="@+id/languages_from"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:prompt="@string/from_languages_prompt" />

The Spinner elements allows you to define a select box. Here, we have two ones. One for the input language and one for the output.

1
2
3
4
5
6
<EditText
    android:id="@+id/text_to_translate"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:background="@android:drawable/editbox_background"
    android:prompt="@string/text_to_translate" />

The EditText element is a text field to be filled by the user.

1
2
3
4
5
6
<Button
    android:id="@+id/translate_button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentRight="true"
    android:text="@string/translate_button" />

In order to tell the application that we’ve finished typing the phrase and that we’re ready to get it’s translation, we add here a button.

1
2
3
4
<TextView
    android:id="@+id/translated_text"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" />

Finally, we add a non editable text field which will contain the translated string.

Translation strings

spinner When, later, we will execute the application we’re currently programming, you’ll be able to click on the spinner and select a language.

Then you’ll the screenshot on the left. As you can see, we have a small phrase telling “pick a language to translate from”.

This string is the attribute android:prompt of the spinner.

 
android:prompt="@string/from_languages_prompt"

We call here the I18n translations strings. Let’s open res/values/strings.xml

Our file looks like this :

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8">
<resources>
    <string name="app_name">Translator</string>
    <string name="from_languages_prompt">Choose a language to translate from</string>
    <string name="to_languages_prompt">Choose a language to translate to</string>
    <string name="text_to_translate">The text you wish to translate</string>
    <string name="translate_button">Translate!</string>
</resources>

We put here all our strings and this will be their default translation (usually, english).

You can see than in main.xml, we’re making calls to @strings/xxx. As you might have understood, @strings is the name of the file. You can create as many translation files as you wish.

If we wish to add a french translation to our application, we’ll have to create res/values-fr/strings.xml Which will contain :

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8">
<resources>
    <string name="app_name">Translator</string>
    <string name="from_languages_prompt">Langue d'origine</string>
    <string name="to_languages_prompt">Langue de destination</string>
    <string name="text_to_translate">Texte à traduire</string>
    <string name="translate_button">Traduire !</string>
</resources>

It’ll automatically get the appropriate translation depending of the phone’s parameters.

Filling the spinners

Our spinner’s content will be the list of all languages that Google Translate can translate from and to.

We will dynamically fill those spinners. The list is available in the library we’re using.

Remember, when you’ve created your project, you’ve defined the name of an “Activity” class which is the default window. If you’ve followed this article to the letter, this activity should be named Main. So let’s open src/com/android/translator/Main.java.

It contains an empty activity, allowing only to load the window.

1
2
3
4
5
6
7
8
9
10
11
package com.android.translator;
import android.app.Activity;
import android.os.Bundle;

public class HelloAndroid extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}

The onCreate method is what we’re interested in. It’s called with a parameter savedInstanceState, which is the current state of the application. We start by calling this onCreate method in the parent class, allowing us to load the require environment by Android for the application.

1
setContentView(R.layout.main);

R.layout.main is an integer. Every element of your interface (the XML elements defined previously) are defined by Java as integers. You can find each of them with it. And as a constant with this integer is defined every time, you can find it even more easily. Here, R.layout.main is the layout/main.xml file. You can define which interface will be displayed by your activity.

As we’ll have to add some content inside our two spinners, we must get their content. They’re identified by integers too. In our spinner, we’ve defined an android:id attribute.

1
android:id="@+id/languages_from"

So we can get the id of our spinner in the constant R.id.languages_from.

1
2
Spinner language_from = (Spinner) findViewById(R.id.languages_from)
Spinner language_to = (Spinner) findViewById(R.id.languages_to)

Ok. Now, let’s fill them.

In order to do that, we’ll have to create an ArrayAdapter, which will be an array with strings. Every element will be an entry of the select box.

1
2
ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

We’ve created that adapter. Let’s add our datas to it.

To add a new element to an adapter, we just need to use the add method.

1
adapter.add("Ma Valeur");

Here, all our values are located in the Google Translate library. We have to loop through all of them and add them.

1
2
3
for (Language l : Language.values()) {
    adapter.add(l.name());
}

Great ! One last thing however. Our adapter has been created but hasn’t been assigned anywhere. We must assign it’s values to our two spinners.

1
2
languages_from.setAdapter(adapter);
languages_to.setAdapter(adapter);

Which gives us, in fine, to get the content of our two spinners :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Spinner language_from = (Spinner) findViewById(R.id.languages_from)
    Spinner language_to = (Spinner) findViewById(R.id.languages_to)

    ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item);
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

    for (Language l : Language.values()) {
        adapter.add(l.name());
    }

    languages_from.setAdapter(adapter);
    languages_to.setAdapter(adapter);
}

Not too lost ? ;-)

The entire project for this application is available on github

Events : click on the button

Our application is starting to look well. However it’s not usable yet. In order to do that, we must be able to click on the button.

We must create a listener on the button click. A function which will be executed at every click.

After the previous code, let’s add our listener :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
findViewById(R.id.translate_button).setOnClickListener(new View.OnClickListener() {
    public void onClick(View v) {
        String text = ((EditText) findViewById(R.id.text_to_translate)).getText().toString();

        try {
            Language lang_from = Translator.getLanguageString((Spinner) findViewById(R.id.languages_from));
            Language lang_to = Translator.getLanguageString((Spinner) findViewById(R.id.languages_to));

            String translatedText = Translator.translate(text, lang_from, lang_to);
            ((TextView) findViewById(R.id.translated_text)).setText(translatedText);
        } catch(Exception e) {
            ((TextView) findViewById(R.id.translated_text)).setText(e.toString());
        }
    }
});

What are we doing here ?

1
findViewById(R.id.translate_button)

We get the button element. Then we call, on this element, the setOnclickListener element. This method takes one OnClickListener element. It’s a function which will be executed at every click on the button.

1
String text = ((EditText) findViewById(R.id.text_to_translate)).getText().toString();

Here, we get the text to translate.

1
2
3
4
5
try {
    // ****
} catch(Exception e) {
    ((TextView) findViewById(R.id.translated_text)).setText(e.toString());
}

If, for any reason, an error occured when trying to translate the content, we wish to display an error by ourselves and not see the application die.

So, if the internet connection isn’t available, it’s not possible to translate the string. An exception would be raised. With the try/catch, we intercept this exception and display it’s content in the text field.

1
2
Language lang_from = Translator.getLanguageString((Spinner) findViewById(R.id.languages_from));
Language lang_to = Translator.getLanguageString((Spinner) findViewById(R.id.languages_to));

We get here the two selected languages. The Translator.getLanguageString must be defined in src/com/android/translator. It contains the following code :

1
2
3
4
5
6
7
8
9
10
public static Language getLanguageString(Spinner spinner) throws Exception {
    String lang = spinner.getSelectedItem().toString();

    for (Language l : Language.values()) {
        if (l.name() == lang) {
            return l;
        }
    }
    throw new Exception("Unknown language provided : " + lang);
}

With the getSelectedItem method, we get the selected language in the spinner. However the Google Translate library requires that we provide it a Language object. Not a string like we have in the spinner.

So we loop through all the available languages until find the one and return it. If no language is found, we raise an exception (which will be then managed by the try/catch seen earlier).

Let’s continue in our action to click on the button.

1
String translatedText = Translator.translate(text, lang_from, lang_to);

Here, we call the Google Translate library to get the translated string.

1
((TextView) findViewById(R.id.translated_text)).setText(translatedText);

And finally, we put that string in the appropriate text field.

Conclusion

Sorry for the (too) long article. Our application is now developed. We just have to install it on the SDK to try it. Then on our telephone to use it. That is described in the article Deploy an Android Application