Android Development

Use intents to start other activities

by Martin on Mar.06, 2009, under tutorial

After working on our first list application and finally adding the user photos to our list we now want to show you how you can use your activity in another context.

This tutorial will show you how you can use a button to open the created contact list to pick a contact and display the name of the picked contact with the “Toast widget”.

The first thing you should do: create another project to be sure to have two working application samples.
Package: com.droidnova.android.samples
Activity name: PickYourDude
Application name: Pick your dude

Lets start again with the layout. First change the name of the main.xml into button.xml because we will define the layout of our main activity where only a text and a button is visible.
After that we define a LinearLayout, a TextView and a Button. Should look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?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:id="@+id/button_info_text"
        android:text="@string/button_info_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:paddingTop="20dip"
        android:paddingBottom="20dip" />
    <Button android:id="@+id/button"
		android:text="@string/button_text"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content"
		android:layout_gravity="center_horizontal" />
</LinearLayout>

From our earlier tutorials this should look familar to you. Please note the paddingTop and paddingBottom which work similar to css paddings as well as the layout_gravity property which is used for relative alignment.

After the button.xml we create a new xml named contact.xml. The content is exactly the same as the main.xml in our first list application and the addon for using photos.
Here is the whole 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
39
40
41
42
43
44
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <ImageView android:id="@+id/contact_image"
        android:src="@drawable/icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
    />
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
        <LinearLayout
            android:orientation="horizontal"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Name: "
            />
            <TextView android:id="@+id/contact_name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
            />
        </LinearLayout>
        <LinearLayout
            android:orientation="horizontal"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Phone: "
            />
            <TextView android:id="@+id/phone_number"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
            />
        </LinearLayout>
    </LinearLayout>
</LinearLayout>

Next task is to define some static strings for our application to display. We need a name for our application, a text to display above the button, a button label, a label for the contact list and the text the Toast widget should display.
So lets modify the strings.xml and define the following:

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">Pick your dude</string>
    <string name="button_info_text">Please choose a contact</string>
    <string name="button_text">Pick</string>
    <string name="contacts">Contacts</string>
    <string name="chosen">You have chosen:</string>
</resources>

Well now we can copy our ListContacts activity from the previous tutorial and rename that to Contacts. We should rename the class because we want to do more with it than just list some contacts.
After renaming the class and correcting the package definition to com.droidnova.android.samples we open the class in our IDE and we will see an error. On line 28 the old layout is still set to “main”. This needs to be changed to “contact”. The rest should be ok.

Now we modify our AndroidManifest.xml and add the Contacts activity. We also define which action can be performed on this activity. We choose PICK and VIEW and the category DEFAULT. The whole xml should look like this.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      android:versionCode="1"
      android:versionName="1.0.0" package="com.droidnova.android.samples">
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.CALL_PHONE" />
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:label="@string/contacts" android:name=".Contacts">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <action android:name="android.intent.action.PICK" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
        <activity android:label="@string/app_name" android:name=".PickYourDude">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

The changes are only from line 8 to 14 where we define the activity, the actions and the category.

The next step is to create the logic. So open up the PickYourDude activity.
The first thing we should notice is the error because the code still uses the R.layout.main. Change it to the button layout.

1
setContentView(R.layout.button);

The text for the TextView is defined in the strings.xml and the reference is in the button.xml so we don’t have to touch the TextView ourself.
The button is also labeled automatically but we have to add an OnClickListener to execute custom code. We create our own OnClickListener named MyOnClickListener as a private inner class in PickYourDude.

1
2
3
4
5
6
private class MyOnClickListener implements View.OnClickListener {
    @Override
    public void onClick(View v) {
        startActivityForResult(new Intent(Intent.ACTION_PICK), PICK_CONTACT);
    }
}

The method “startActivityForResult” accepts an Intent as the first parameter. The Intent has to be constructed with an action you want to trigger. In our case the ACTION_PICK.
The static class variable PICK_CONTACT is like a flag, so that we can distinguish in which context the activity was started. We define it right above our onCreate method.

1
private static final int PICK_CONTACT = 0;

The flag should have at least a non negative value because a value below zero is like calling the startActivity method on which we don’t get a result.

Now we have to add this OnClickListener to our button with two new lines in our onCreate method of PickYourDude.

1
2
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new MyOnClickListener());

The next thing is to implement the PICK logic in our Contacts activity.
We should modify the onListItemClick method right below the line where we set the data for the intent.
First lets get the action on which this activity was started.

1
String action = getIntent().getAction();

If the action is ACTION_VIEW we just want to start the Intent to make the call.

1
2
3
if (Intent.ACTION_VIEW.equals(action)) {
    startActivity(intent);
}

But if the action was ACTION_PICK, we want to set the result and pass the data back.

1
2
3
4
5
6
if (Intent.ACTION_VIEW.equals(action)) {
    startActivity(intent);
} else if (Intent.ACTION_PICK.equals(action)) {
    setResult(RESULT_OK, intent);
    finish();
}

The finish() method just ends the activity to free the resources.
The whole method looks like this.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
protected void onListItemClick(ListView listView, View view, int position, long id) {
    super.onListItemClick(listView, view, position, id);
 
    Intent intent = new Intent(Intent.ACTION_CALL);
    Cursor cursor = (Cursor) myAdapter.getItem(position);
    long phoneId = cursor.getLong(cursor.getColumnIndex(People.PRIMARY_PHONE_ID));
    intent.setData(ContentUris.withAppendedId(Phones.CONTENT_URI, phoneId));
 
    String action = getIntent().getAction();
    if (Intent.ACTION_VIEW.equals(action)) {
        startActivity(intent);
    } else if (Intent.ACTION_PICK.equals(action)) {
        setResult(RESULT_OK, intent);
        finish();
    }
}

Now we have to go back to the PickYourDude activity to implement what we do with the result of the activity. For that we need to override the onActivityResult method to implement our own logic.
The first parameter is the requestCode we set with the flag at the call of startActivityForResult(). In our case we check if the parameter is PICK_CONTACT.

1
2
3
4
5
6
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == PICK_CONTACT) {
        // todo
    }
}

Next we check if the result is ok which is set on calling the method setResult in the Contracts activity.

1
2
3
4
5
6
7
8
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == PICK_CONTACT) {
        if (resultCode == RESULT_OK) {
            // todo
        }
    }
}

In a more complete method you might want to add more sophisticated conditions to react should result not be “OK” for example.

Now we have to use the data for a content query and get the data we want, in our case the name of the contact.

1
2
3
4
5
6
7
8
9
10
11
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == PICK_CONTACT) {
        if (resultCode == RESULT_OK) {
            Cursor contact = getContentResolver().query(data.getData(), null, null, null, null);
            contact.moveToFirst();
            String name = contact.getString(contact.getColumnIndexOrThrow(People.NAME));
            Toast.makeText(this, getString(R.string.chosen) + " " + name, Toast.LENGTH_LONG).show();
        }
    }
}

We know how to use a Cursor so lets use one. Please don’t forget to move to the first entry of the cursor because the cursor does not point to a result by default.
After that we get the name of the contact using the Cursor and finally start the Toast widget. The widget needs a context, a string and the duration to display itself. Finally we call the show() method to display the widget.

The complete activity looks like that.

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
39
40
41
42
package com.droidnova.android.samples;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.Contacts.People;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
 
 
public class PickYourDude extends Activity {
    private static final int PICK_CONTACT = 0;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.button);
 
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new MyOnClickListener());
    }
 
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == PICK_CONTACT) {
            if (resultCode == RESULT_OK) {
                Cursor contact = getContentResolver().query(data.getData(), null, null, null, null);
                contact.moveToFirst();
                String name = contact.getString(contact.getColumnIndexOrThrow(People.NAME));
                Toast.makeText(this, getString(R.string.chosen) + " " + name, Toast.LENGTH_LONG).show();
            }
        }
    }
 
    private class MyOnClickListener implements View.OnClickListener {
        @Override
        public void onClick(View v) {
            startActivityForResult(new Intent(Intent.ACTION_PICK), PICK_CONTACT);
        }
    }
}

As you can see we used some different intents, overrode methods, extended different classes and used different layouts. Equipped with this basics you should be able to start some not-so-simple applications by yourself.

For any improvements, questions and/or hints feel free to comment.

  • Share/Bookmark
:, , , , ,

10 Comments for this entry

  • Ben

    Thanks! This helped me a lot.

  • DaRolla

    Hi,

    nice little tutorial. I am missing these lines to change the language / locale in order to activate the different resources:

    Resources resource = super.getResources();
    Configuration cf = resource.getConfiguration();
    DisplayMetrics dm = resource.getDisplayMetrics();
    cf.locale = new Locale(“de”);
    resource.updateConfiguration(cf, dm);

    Greetings,
    DaRolla

  • Claudio

    Thanks for your input, guys. Any comment is appreciated !!

  • chabfive

    Hi,

    How can I modify the application name (the name under the application icon) at the time of the installation?

    Without to create a specific app for each language.

    I want that the app name be contingent upon the local.

    Thanks

  • Martin

    Hi chabfive,

    you can find the answer on my post about Make use of simple mulitlanguage support.

  • chabfive

    Hi Martin,

    I’m sory but I don’t understand.

    With your solution you need to launch at least one time the app to change the app name. It’s right?

  • Martin

    Hey,

    no thats not correct. In your Manifest you have used this line of code:

    1
    
    <application android:icon="@drawable/icon" android:label="@string/app_name">

    That means that android check your locale and display in the main menu the app_name you defined in your string.xml

    You can check that on the emulator! It is directly active after installing the application. And it will change without starting the app if you change your locale.

  • Wollis

    Hi,
    I really appreciate this tutorial. But I do not understand these lines in Manifest.xml:

    What exactly does it mean? (I’m newbie in this field so please be patient :) )
    I cannot see any class whit name Contacts. Is there some other part of this tutorial where is class Contacts implemented?
    Thanks for your comment.

  • Wollis

    Hey where are my lines?!
    So once again. I mean line 8 to 15 in Manifest.xml

  • Martin

    Hi Wollis,

    sorry, Wordpress strips your lines without warning. It always do so if you post html/xml tags :/

    Anyway, this application was created with SDK 1.1 as far as I can remember.

    I know that the Contacts where changed during SDK updates, so please look at the official documentation for more information.

    I will update this example asap.

Leave a Reply