Starting Sub Activities

An essential thing in the lifetime of an application, that is more sophisticated than a HelloWorld Application, is to start other Activities, especially SubActivitites. Let's assume the following scenario:

We want to have something like an InputDialog where the user can write a keyword he wants to search on Google for.

So we will create a new Android Project as we already did it before. The first thing we will do is to add a second Activity we will name

"MySecondActivity".

In the beginning the code shall look like this:

package org.anddev.andbook.startingsubactivities;

import android.app.Activity; import android.os.Bundle;

public class MySecondActivity extends Activity {

/** Called when the activity is first created. */ @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.rnain);

We now will add a Button to the first Activity. We do that by altering the main.xml, of course, and not by switching to a Java UI.

Browse to "/res/layout/main.xml" and you will see code similar to this:

<?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" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content"

android:text="Hello World, StartingSubactivities" /> </LinearLayout>

Note: maybe Eclipse opened the main.xml with its default xml-Editor which is not of any use for us. Since SDK-version m5 the ADT plugin provides a Resource-Editor with Syntax-Highlighting.

> drawable j & layout

Oper F3 J

Open With ►

CI

Android Layout Editor

[x] main.xml

Showln Ait+Shift+W ►

M

Android Resource Editor

> {¿j? values G AndroidMariifesI

B

Copy Ctil+C

i

Text Editor XML Editor

Picture 17 Opening the Resource Editor If we would start the Application right now it would look like this:

03 Starting Subactivities

Hello World, StartingSubactivities

Picture 18 Layout default (sdk-version m5)

As we want to have a Button in our application, we will have to come up with some xml-code:

<Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Open Search-Dialog" />

As one can imagine, "fill_parent" makes a View us all space the parent View provides and "wrap_content" uses just as much layout space as it needs to display its content correctly.

So our button will fill the whole screen in width and wrap around the "Open Search-Dialog" we typed for the android:text attribute.

Our application now looks like this:

Picture 19 Layout with Button (sdk-version m5)

When we now click the button - nothing happens, of course. We will have to apply a Listener to be specific an OnClickListener to Handle clicks to this Buttons.

But wait... how can we refer to that Button in Java Code ?

Finding XML-defined Views in Java-Code

To find a View that was defined in XML we first have to add one single line to the XML-definition of that View, an android: id attribute. In this case we will give it the id "btn_open_search":

<Button

android

id="@+id/btn open search"

android

layout width="fill parent"

android

layout height="wrap content"

android

text="Open Search-Dialog" />

Finding that View in Java Code is same easy. Within an Activity you can use the findViewById(int resourceID) method, to get a reference to a View using the android:id that has been defined in XML.

The same can be done with any other class that extends View, i.e. EditText, TextView, MapView, etc...

But findViewById(...) can only be used with Views that are placed within the Layout that was loaded to that Activity using setContentView(...) !

Coming back to our example, we add the following in Code to onCreate(.), right after the setContentView(...):

Button b = (Button)this.findViewById(R.id.btn_open_search);

If Eclipse cannot find i.e. the Button-Class, just hit 'CTRL+SHIFT+O' what will organize the imports and automatically add (in this case):

import android.widget.Button;

Handling Clicks to Views

We now remember that we once © wanted to make our button clickable. Therefore we simply set an anonymous OnClickListener to our Button:

b.setOnClickListener(new OnClickListener(){ public void onClick(View arg0) {

// Place code to handle Button-Click here.

Note: Eclipse might not recognize the following import by itself:

import android.view.View.OnClickListener;

Now we will add an Intent to the onClick-Event that will start our SubActivity:

/* Create an Intent to start

* MySecondActivity. */ Intent i = new Intent(

StartingSubactivities.this, MySecondActivity.class); /* Send intent to the OS to make

* it aware that we want to start

* MySecondActivity as a SubActivity. */ startSubActivity(i, 0x1337);

The second parameter of startSubActivity can be any unique Integer. It will get useful later on (then we will be placing it declared as final to our Activity), when we want to retrieve a result from the SubActivity.

If we would now run our code and click our button we would receive the following error-message:

1-

& Q 4:08 PM I

o:

Application Error:

He

org.anddev.andbook.startingsubactivities

An error has occurred in org.anddev.andbook.startingsubactivities. Unable to find explicit activity class

{org.anddev,andbook.startingsubactivitiesyorg.andd ev.andbook.startingsubactivities. MySecondActivity}; have you declared this activity in your Android Manifest.xml?.

!

Force Quit

Picture 20 Activity not defined in AndroidManifest.xml (D Note: Some of the messages shown are really helpful, read them.

Picture 20 Activity not defined in AndroidManifest.xml (D Note: Some of the messages shown are really helpful, read them.

So we need to define our "MySecondActivity" in the

AndroidManiufest.xml too. Just after the first </activity> tag we write:

<activity android:name="

MySecondActivity"

android:label=

'@string/app name">

<intent-filter>

<action

android:name=

'android.intent.action.VIEW" />

<category

android:name=

'android.intent.category.DEFAULT" />

</intent-filter>

</activity>

This time we did not choose "...MAIN" for <action> and "...LAUNCHER" for <category> because there is no need to get "MySecondActivity" launched from outside of our Application.

"MySecondActivity" is now reachable through a click to the button, but it also refers to our main .xml:

setContentView(R.layout.main);

So we have to create an additional layout file for "MySecondActivity". It will contain a so called EditText what in Swing jargon would be a TextField and another Button to return to our "Main"-Activity:

<?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/et keyword"

android

layout_width="fill_parent"

android

layout_height="wrap_content"

/>

<Button

android

id="@+id/btn_return"

android

layout_width="fill_parent"

android

layout_height="wrap_content"

android

text="Submit" />

</LinearLayout>

Of course both need an android:id that we can use the in our JavaCode. Now we can change the setContentView of

"MySecondActivity" to:

this.et_keyword = (EditText)this.findViewById(R.id.et_keyword);

/* Get the return-Button from the XML-file. */ Button b = (Button)this.findViewById(R.id.btn_return); /* Make that Button handle clicks to itself. */ b.setOnClickListener(new OnClickListener(){ public void onClick(View arg0) {

/* Place code to handle Button-Click here. */

Returning values from SubActivities

Returning values from SubActivities to the caller is also very simple:

/* Retrieve the Text from the EditText. */ String keyword =

MySecondActivity.this.et_keyword.getText().toString(); /* The parameters passed to this function

* will be available to the caller. */ MySecondActivity.this.setResult(1, keyword); /* Our Activity is done and shall be closed. */ MySecondActivity.this.finish();

One could additionally pass a so called Bundle back to the caller (what is more or less a HashMap), but I'll tell you more of that soon.

Obviously the caller has to react on the fact that the SubActivity decided to return. To accomplish that, we have to override a single method coming from the Activity class. It is called onActivityResult(...):

@Override protected void onActivityResult(int requestCode, int resultCode, String data, Bundle extras) { /* Place out code to react on Activity-Result here. */ super.onActivityResult(requestCode, resultCode, data, extras);

You probably recognized that the first parameter is called requestCode - yes it is the same requestCode that we passed to startSubActivity earlier. So if we have more than one SubActivity, we can use requestCode to differentiate which SubActivity has just returned.

Tipp: Eclipse provides a very useful function that you'll learn to love, especially if you are extending a base-class and search for methods to override:

Picture 21 Using Eclipse to find methods to override

So now we can simply switch on the requestCode and create another Intent to do the Google-search.

/* Check which SubActivity returned.

case MYSECONDACTIVITY_REQUESTCODE: /* Create a new Intent to

* show the Google-Search Page

* with the keyword returned. */ Intent webIntent = new Intent(

android.content.Intent. VIEW_ACTION,

Uri.parse("http://www.google.com/search?q=" + data)), startActivity(webIntent); break;

As you probably have recognized this time we are creating the Intent another way. Last time we said like: "We want to start XYZ.class", but this time we describe what we want to get done. We want to VIEW a URI (Uniform Resource Indicator), which can be constructed by using i.e.

Our Application is now capable of starting a (Sub)Activity, grabbing its results and launching the Browser using an Intent.

But how to pass data to a (Sub)Activity?

0 -1

Post a comment