Mobile Phone Handheld Hardware Hardware Rick Rogers John Lombardo O'Reilly Media, Inc. O'Reilly Media Android Application Development, 1st Edition13.1. Intents: Simple, Low-Overhead IPCThe Android system uses Intent objects to
enable applications to specify an Activity or Service.
Intent objects also deliver data from one application
to another, providing a simple and convenient form of IPC. The Intent class, the Activity class, and Android's Intent-based
inter-process communication solve one of the user interface problems of
smartphone platforms that support multiple separate applications: they
feel like a collection of separate programs. You don't have the simplicity
of navigating a hierarchical user interface, as in simpler feature phones,
and you don't have multiple windows, as on a PC user interface. The way
Activities work together on Android makes it possible to make a seamless
user interface out of multiple applications, and inter-process
communication can enhance cooperation among applications. 13.1.1. Intent Objects Used in Inter-Process CommunicationWe'll start with how the client makes a request. Several classes
are involved:
Activity and
Context We've seen Activity
objects used throughout this book. The Context class, a parent class of
Activity and Service, contains the methods for
sending Intent objects from one
Activity object to another,
whether in the same process or a different one. So every place you
have an Activity subclass—
which is nearly every place in your application that needs to
display a UI—you have the methods for slinging Intent objects around to other Activity
instances elsewhere in the Android system.
Intent Intent objects are passed from process to process, using
methods such as startActivity and startActivityForResult. The Intent class itself
provides constructors, accessors, and other utilities for handling
the content of an Intent object, but no methods
for moving Intent objects. An important set of accessors are those named putExtra. Several methods with this name
and different arguments—hence different signatures—let you attach
"extra" data to an Intent. This data can be used for
general-purpose inter-process communication. The first examples in
this chapter will use this kind of simple inter-process
communication.
13.1.2. Activity Objects and Navigating the User Interface
HierarchyMost mobile handset user interfaces consist of a linked web, or
hierarchy, of "screens"—user
interface views that occupy the whole screen, except for areas where
titles and indicator icons are displayed and where soft-key labels (if
any) are displayed. Usually, these hierarchies are implemented by a
single program that manages a "stack" of screens backward from the
current screen (and sometimes forward, as well, as in an iPod-like UI).
Intent and Activity objects work together, using inter-process
communication, to link different parts of different applications' user
interfaces into a coherent user experience with navigation that is
unified and seamless when moving between applications. In this section
we'll show how UI navigation and inter-process communication go hand-in-hand. 13.1.3. Example: An Intent to Pick How We Say "Hello World"Almost everyone writes "Hello World" programs. So there is a
nearly universal need to augment these programs and prevent them from
getting dull by providing a choice of greetings. That is what Example 13-1 does. Example 13-1. An Intent that chooses alternate "Hello World" stringspackage example.sayhello;
import example.sayhello.R;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
/**
* An activity returning a result
*/
public class SayHello extends Activity
{
protected void onCreate(Bundle savedInstanceState)
{
// Call the parent class
super.onCreate(savedInstanceState);
// Put up the view for acquiring some input from the user
setContentView(R.layout.main);
// Set up the listeners for the buttons
((Button)findViewById(R.id.hello)).setOnClickListener(helloListener);
((Button)findViewById(R.id.goaway)).setOnClickListener(goAwayListener);
}
private OnClickListener helloListener = new OnClickListener()
{
public void onClick(View v)
{
returnResult("Hello, other Android!");
}
};
private OnClickListener goAwayListener = new OnClickListener()
{
public void onClick(View v)
{
returnResult("Get off my lawn, damn kids!");
}
};
// Put a result in an Intent object and set the result for this activity
void returnResult(String greeting) {
// Create the Intent object
Intent i = new Intent();
// Put an extra named "result" in the intent
i.putextra("result", greeting);
// Make this Intent the result for this activity
setResult(RESULT_OK, i);
// End this activity
finish();
}
}
|
Example 13-2 shows the layout
file that specifies the user interface provided by this activity. Example 13-2. Resource for alternate "Hello World" strings<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:padding="4dip"
android:gravity="center_horizontal"
android:layout_width="fill_parent" android:layout_height="fill_parent">
<TextView
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:layout_weight="0"
android:paddingBottom="8dip"
android:text="Say hello, or not"/>
<Button android:id="@+id/hello"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:text="Hello">
<requestFocus />
</Button>
<Button android:id="@+id/goaway"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:text="Go away">
</Button>
</LinearLayout>
|

This layout describes a screen with two buttons. The listeners for
these buttons are called HelloListener and GoAwayListener. In the Java code in Example 13-1, the listener methods call
returnResult, passing the string that
will be returned. You can try this program as a standalone application. Create a new
Android project with the package named example.sayhello and an activity named
SayHello. Use Example 13-1 for the SayHello class and Example 13-2 for the main.xml layout file. When run, the
application will display Figure 13-1. When you click on or press one of the buttons, the program
finishes and disappears from the screen. It also creates an
Intent object used as a "result" for the activity.
Let's take a closer look at how it
does that. You may want to run the program under the debugger and set a
breakpoint on the first line of the returnResult method, where we create an
Intent object, and follow along using
the "step over" command in the debugger. First, an Intent object is
created. This is what gets moved from this process to the process that
started this Activity: // Create the Intent object
Intent i = new Intent();
Here we will see how Intent
objects facilitate inter-process communications: you can label and
associate several types of data with an Intent object and send these "stowaways" with
the object from one process to another. Here we call putExtra to add data to the Intent. Its first
argument is a String that labels the
data; here we use "result" as the label. The second argument, the actual
payload, can be any data type supported by the different
putExtra methods (which differ in the arguments they
take); in our simple example, we use a String for the payload as well: // Put an extra named "result" in the intent
i.putExtra("result", greeting);
The returnResult method "returns" the result,
not to the method that calls this method, but through an
Intent object to the code that started this instance
of SayHello. The following line sets
the result: // Make this Intent the result for this activity
setResult(RESULT_OK, i);
In this example, however, nothing happens to our result. Nobody
expects it, and nobody uses it. Next we will change that, and see how
one application can use a result produced by another. 13.1.4. Getting a Result via Inter-Process CommunicationThis section modifies the "Hello World" application from an earlier
chapter to show how Android can make separate Activity objects in
separate programs seem of-a-piece. This version uses one Activity to
enable the user to choose which greeting to put on the screen in another
Activity. A copy of the data put into the Intent
object in the previous section ends up in an Intent
object in the HelloWorldActivity
Activity. To enable a client to find the Intent, the server assigns it a
label called an action. In this case, we'll call
our action PICK, shown here in Example 13-3. Example 13-3. HelloWorldActivity.javapackage example.helloworld;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.TextView;
public class HelloWorldActivity extends Activity {
TextView helloView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Make a text view and set it to be the content view
helloView = new TextView(this);
setContentView(helloView);
// Make an Intent instance to fill in
Intent helloIntent = new Intent();
// Set the action, and type
helloIntent.setAction("android.intent.action.PICK");
helloIntent.setType("vnd.example.greeting/vnd.example.greeting-text");
// Ask an activity that matches our Intent object
startActivityForResult(helloIntent, 0);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent result)
{
if (resultCode == RESULT_OK) {
String greeting = result.getStringExtra("result");
helloView.setText(greeting);
}
}
}
|
The changes we made will start an Activity in a separate
application and a separate process to provide the user interface for
selecting a greeting. After that greeting is returned by the other
Activity, this one uses it to say hello. Run the program. You will see the user interface presented by the
SayHello program, just as in Figure 13-1. But this time, when you
press one of the two buttons, the screen will display the greeting you
selected (Figure 13-2). 
Let's take a closer look at how it's done. Here, again, you may
want to follow along using the debugger. NOTE Did you run the SayHello
program yet? You need to do that before you run our modified HelloWorldActivity program. The Android
emulator installs programs the first time you run them, so once you
run SayHello it will stay around as
long as the emulator is running. But if the program hasn't been run
yet, the startActivityForResult
call in the current example will fail, because Android cannot find
SayHello. First, we need to start our helper application, which we do using
an Intent object: // Make an Intent instance to fill in
Intent helloIntent = new Intent();
Then, we need to specify an Activity that is neither a part of our
application nor part of an Activity in any of the programs that come
with Android: // Set the action, and type
helloIntent.setAction("android.intent.action.PICK");
helloIntent.setType("vnd.example.greeting/vnd.example.greeting-text");The setType method requires a
MIME type. We will use a vendor-specific MIME type unique to our purpose (by vendor here, I mean us).
As a result, our SayHello activity is
launched because it has an Intent filter that matches the parameters we
have set in this Intent
object. Now we call the startActivityForResult method, passing the Intent object we created to
hold the information that tells the Android framework to find an
Activity matching the specifications in our Intent: the PICK action and the requested MIME type. We
don't explicitly request the SayHello
Activity—we might want to replace it with something else at some
point—but for now, that activity is what Android will find: // Ask an activity that matches our Intent object
startActivityForResult(helloIntent, 0); The startActivityForResult
method navigates to a UI that obtains information and returns it. This
is a good illustration of using IPC for a task that could otherwise have
required redundant code in all applications that need similar
information. Now SayHello should run and display its user
interface for selecting a greeting. When you have selected a greeting
and the setResult method is called,
Android's inter-process communication system will move the result to
this process, and the OnActivityResult method will be called. We've
defined it as follows: protected void onActivityResult(int requestCode, int resultCode, Intent result) {
if (resultCode == RESULT_OK) {
String greeting = result.getStringExtra("result");
helloView.setText(greeting);
}The method calls getStringExtra
to access the greeting we have chosen. It uses the setText method of the TextView class to display our selected
greeting. To summarize, in this example one program (SayHello) acquires some information and
supplies it to another program (HelloWorldActivity). We have successfully used
inter-process communication. Android includes a component system based on remote objects and
methods, which we'll examine in the next section. This is a powerful
feature with many uses, but remote method calls are overkill in many
cases. As you design your programs, first consider whether your
inter-process communications needs fit what Intents and the Context class's Intent-related methods can do.
Particularly when you're using inter-process communication to provide a
user interface in an Activity, this high-level form of IPC is easy to
use and appropriate to the task.
|