Taste of Android :: Part-4


Bhaskar S 05/18/2013


Android Application Development - III

A real-world Android application will typically have more than one Activity. So how do we navigate from one Activity to another ? Enter Intents !!! An Intent is instance of the Android framework class android.content.Intent, using which one can trigger an asynchronous event to the Android system for launching another Activity. An Intent is triggered by invoking the startActivity() method on an Activity.

The best way to understand any concept is through an example. So let us create a new Android application named DroidMultiActivity to illustrate the concept of navigating from one Activity to another using an Intent. This is a quiz application with two Activities - one is the main Activity that displays two buttons Start and Exit to the user. Clicking on the Start will display the quiz Activity which displays a question and expects the user to type the answer in a text box. Also, there are three buttons Submit, Next, and Done. Clicking on the Submit button checks the answer entered by the user and display a message if it it correct or the answer if it is wrong. Clicking on the Next button displays the next question, and clicking on the Done button closes this Activity and takes the user to the main Activity. So without further ado, lets get started. We will not go step-by-step to show the various screens since we already did that in Part-2 for the DroidTipCalculator application.

Modify the contents of the dimens.xml file to look like the one shown in the listing 4.1 below:

Listing-4.1
<?xml version="1.0" encoding="utf-8"?>
<resources>

<dimen name="title_size">26sp</dimen>
<dimen name="question_size">20sp</dimen>

</resources>

Next, modify the contents of the strings.xml file to look like the one shown in the listing 4.2 below:

Listing-4.2
<?xml version="1.0" encoding="utf-8"?>
<resources>

<!-- id references -->

<string name="button1">button1</string>
<string name="button2">button2</string>
<string name="button3">button3</string>
<string name="button4">button4</string>
<string name="button5">button5</string>
<string name="textview1">textview1</string>
<string name="edittext1">edittext1</string>

<!-- text references -->

<string name="app_name">DroidMultiActivity</string>
<string name="action_name">com.polarsparc.android.ACTIVITY_TWO</string>
<string name="quiz_title">Quiz Me !!!</string>
<string name="action_settings">Settings</string>
<string name="start_quiz">Start Quiz</string>
<string name="exit">Exit</string>
<string name="confirm">Confirm</string>
<string name="answer">Your Answer</string>
<string name="submit">Submit</string>
<string name="next">Next</string>
<string name="done">Done!</string>

<!-- Array references -->

<string-array name="questions">
<item>Who developed C++ ?</item>
<item>Who created JAVA ?</item>
<item>Who developed LISP ?</item>
<item>Who created PASCAL ?</item>
<item>Who developed PERL ?</item>
</string-array>

<string-array name="answers">
<item>Bjarne Stroustrup</item>
<item>James Gosling</item>
<item>John McCarthy</item>
<item>Niklaus Wirth</item>
<item>Larry Wall</item>
</string-array>
</resources>

As can be inferred from the above listing, we have and array for the quiz questions and an array for the corresponding answers.

We will have two Activity files - the main is named activity_one.xml and the other is named activity_two.xml.

The contents of the activity_one.xml layout file will look like the one shown in the listing 4.3 below:

Listing-4.3
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/quiz_title"
android:textColor="#cc3300"
android:textSize="@dimen/title_size"
android:textStyle="bold"
android:typeface="sans" />

<Button
android:id="@+id/button1"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/start_quiz" />

<Button
android:id="@+id/button2"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/exit" />

</LinearLayout>

Previewing the activity_one.xml layout file in the Graphical Mode in Eclipse will look like the one shown in the figure 4.1 below:

Activity One Image
Figure-4.1

The contents of the activity_two.xml layout file will look like the one shown in the listing 4.4 below:

Listing-4.4
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<TextView
android:id="@+id/textview1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:textColor="#cc3300"
android:textSize="@dimen/question_size"
android:textStyle="bold"
android:typeface="sans" />

<EditText
android:id="@+id/edittext1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/answer" />

<Button
android:id="@+id/button3"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/submit" />

<Button
android:id="@+id/button4"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/next" />

<Button
android:id="@+id/button5"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/done" />

</LinearLayout>

Previewing the activity_two.xml layout file in the Graphical Mode in Eclipse will look like the one shown in the figure 4.2 below:

Activity Two Image
Figure-4.2

Next, modify the contents of the AndroidManifest.xml file to look like the one shown in the listing 4.5 below:

Listing-4.5
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.polarsparc.android.droidmultiactivity"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
android:minSdkVersion="9"
android:targetSdkVersion="14" />

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.polarsparc.android.droidmultiactivity.ActivityOne"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<activity
android:name="com.polarsparc.android.droidmultiactivity.ActivityTwo"
android:label="ActivityTwo" >
<intent-filter>
<action android:name="com.polarsparc.android.ACTIVITY_TWO" />

<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>

</manifest>

We need to unravel information relating to Intent from the AndroidManifest.xml file. From the Listing 4.5 above, we see that we have defined the two activities ActivityOne and ActivityTwo. Of interest is the element <intent-filter>.

The element <intent-filter> specifies the Intent(s) for which the Activity will respond to. The element <intent-filter> must include at least one <action> element and at least one <category> element.

The <action> element defines the action to be performed (which in our case is to launch an activity) and associates a name with it.

The <category> element provides additional information to the Android system. For example, the value of android.intent.category.LAUNCHER indicates the corresponding Activity is the main or initial activity while the value of android.intent.category.DEFAULT indicates the corresponding Activity is the default activity.

Finally, we will have two java source files corresponding to the two Activity files - the main is named ActivityOne.java and the other is named ActivityTwo.java.

The contents of the java source file ActivityOne.java will look like the one shown in the listing 4.6 below:

Listing-4.6
package com.polarsparc.android.droidmultiactivity;

import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.content.Intent;
import android.widget.Button;
import android.content.Context;
import android.app.AlertDialog;
import android.content.DialogInterface;

public class ActivityOne extends Activity {
final Activity act = this;
final Context ctx = this;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_one);

// Start Quiz button
Button startBtn = (Button) findViewById(R.id.button1);

/*
* When we click the Start Quiz button, we want to launch the other
* activity that as questions and prompts for answers
*/
startBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String action = getResources().getString(R.string.action_name);

Intent in = new Intent(action);

startActivity(in);
}
});

// Exit button
Button exitBtn = (Button) findViewById(R.id.button2);

/*
* When we click the Exit button, we want to launch a dialog box to
* confirm we really want to exit
*/
exitBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);

builder.setTitle(R.string.confirm)
.setMessage("Click Yes to Exit!")
.setCancelable(false)
.setPositiveButton("Yes",new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dg, int id) {
// Close this activty
act.finish();
}
})
.setNegativeButton("No",new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dg, int id) {
// Cancel the dialog box
dg.cancel();
}
});

AlertDialog dbox = builder.create();
dbox.show();
}
});
}

}

From the code Listing 4.6 above, we see that when one clicks on the Start Quiz button, we create an instance of Intent object with the action name com.polarsparc.android.ACTIVITY_TWO (this has to match the action name in the AndroidManifest.xml file) and trigger an event to the Android system by invoking the startActivity() method. This in effect will launch the quiz activity ActivityTwo.

On the other hand, when one clicks the Exit button, a dialog box is launched to confirm if one really wants to quit. A dialog box is created using the Android framework class AlertDialog.Builder.

The contents of the java source file ActivityTwo.java will look like the one shown in the listing 4.7 below:

Listing-4.7
package com.polarsparc.android.droidmultiactivity;

import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.EditText;
import android.widget.Toast;
import android.content.Context;
import android.app.AlertDialog;
import android.content.DialogInterface;

public class ActivityTwo extends Activity {
final Activity act = this;
final Context ctx = this;

int pos = 0;

String[] questions = null;
String[] answers = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_two);

questions = getResources().getStringArray(R.array.questions);
answers = getResources().getStringArray(R.array.answers);

final TextView questionFld = (TextView) findViewById(R.id.textview1);
questionFld.setText(questions[pos]);

final EditText answerFld = (EditText) findViewById(R.id.edittext1);

final Button submitBtn = (Button) findViewById(R.id.button3);

/*
* When we click the Submit button, we will pick the answer submitted
* by the user and compare to the actual answer
*/
submitBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String ansStr = answerFld.getText().toString();
if (ansStr != null && ansStr.isEmpty() == false) { // Requires minimum SDK version of 9
if (ansStr.equalsIgnoreCase(answers[pos])) {
Toast.makeText(ctx, "Correct!!!", Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(ctx, "Wrong - Correct answer is " + answers[pos],
Toast.LENGTH_SHORT).show();
}
}
}
});

final Button nextBtn = (Button) findViewById(R.id.button4);

/*
* When we click the Next button, we will pick the next question to be asked,
* display it for the user and clear the previous answer
*/
nextBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
pos++;
if (pos >= questions.length) {
pos = 0;
}
questionFld.setText(questions[pos]);
answerFld.setText("");
}
});

// Done button
final Button doneBtn = (Button) findViewById(R.id.button5);

/*
* When we click the Done button, we want to launch a dialog box to
* confirm we really want to exit
*/
doneBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);

builder.setTitle(R.string.confirm)
.setMessage("Click Yes if Done!")
.setCancelable(false)
.setPositiveButton("Yes",new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dg, int id) {
// Close this activty
act.finish();
}
})
.setNegativeButton("No",new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dg, int id) {
// Cancel the dialog box
dg.cancel();
}
});

AlertDialog dbox = builder.create();
dbox.show();
}
});
}

}

When the quiz activity ActivityTwo is launched, the user is presented with a question and expects the user to key in the answer in the text box. Once the user clicks the Submit button, the answer provided by the user in the text box is verified against the actual answer. If the answer matches, a brief message is displayed indicating the provided answer is correct. However, if the answer does not match, a brief message is displayed indicating the provided answer is wrong and the correct expected answer. We use the Andoid framework class Toast to display a brief message to the user.

Clicking on the Next button presents the next question to the user.

Clicking on the Done button will display a dialog box to confirm if the user really wants to quit. If the user click on the Yes button, the quiz activity is closed and the user is returned to the main activity.

We are now ready to test our DroidMultiActivity application on the virtual Android device we created in Part-1. We will create a Run Configuration for DroidMultiActivity as we did in Part-2 for DroidTipCalculator.

Once the run configuration for DroidMultiActivity is ready, we will Run the application and the application will come to life. Click on the Start Quiz button as shown in the following figure 4.3 below:

Start Quiz Image
Figure-4.3

This will bring us to the quiz activity screen as shown in the following figure 4.4 below:

Quiz Activity Image
Figure-4.4

Key in the answer in the text box and click on the Submit button. Since Bjarne Stroustrup is the correct answer, we will see the Correct!!! message as shown in the following figure 4.5 below:

Quiz Activity Image
Figure-4.5

Click on the Next button and we should see the next question as shown in the following figure 4.6 below:

Quiz Activity Image
Figure-4.6

This time key in a wrong answer in the text box and click on the Submit button. Since Brian is not the correct answer, we will see the Wrong - Correct answer is James Gosling message as shown in the following figure 4.7 below:

Quiz Activity Image
Figure-4.7

Clicking on the Done button will display the user confirmation dialog box as shown in the following figure 4.8 below:

Quiz Activity Image
Figure-4.8

Click on Yes to confirm and we are taken back to the main activity screen. Clicking on Exit button will display the user confirmation dialog box as shown in the following figure 4.9 below:

Start Quiz Image
Figure-4.9

Clicking on Yes to confirm will exit the application.


References

Taste of Android :: Part-1

Taste of Android :: Part-2

Taste of Android :: Part-3