Next   Previous section   Next section

Mobile Phone Handheld Hardware Hardware Rick Rogers John Lombardo O'Reilly Media, Inc. O'Reilly Media Android Application Development, 1st Edition

13.1. Intents: Simple, Low-Overhead IPC

The 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 Communication

We'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 Hierarchy

Most 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" strings

package 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>

Figure 13-1. Output of simple "Hello World" program


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 Communication

This 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.java

package 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).

Figure 13-2. Output of "Hello World" program after user selection


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.

          
    Next   Previous section   Next section
     


    Been Providing Reliable forex Trading signals.