Lessons
-
Sending the User to Another App
- Shows how you can create implicit intents to launch other apps that can perform an action. Getting a Result from an Activity
- Shows how to start another activity and receive a result from the activity. Allowing Other Apps to Start Your Activity
- Shows how to make activities in your app open for use by other apps by defining intent filters that declare the implicit intents your app accepts.
Sending the User to Another App
setType()定义MIME type,可以通过putExtra()携带额外数据
Intent
. The Android system then starts an app that's able to show the address on a map.
Implicit intents do not declare the class name of the component to start, but instead declare an action to perform. The action specifies the thing you want to do, such as view, edit, send, or get something. Intents often also include data associated with the action, such as the address you want to view, or the email message you want to send. Depending on the intent you want to create, the data might be a Uri
, one of several other data types, or the intent might not need data at all.
If your data is a Uri
, there's a simple Intent()
constructor you can use define the action and data.
For example, here's how to create an intent to initiate a phone call using the Uri
data to specify the telephone number:
Uri number = Uri.parse("tel:5551234"); Intent callIntent = new Intent(Intent.ACTION_DIAL, number);
When your app invokes this intent by calling startActivity()
, the Phone app initiates a call to the given phone number.
- View a map:
// Map point based on address Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California"); // Or map point based on latitude/longitude // Uri location = Uri.parse("geo:37.422219,-122.08364?z=14"); // z param is zoom level Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);
- View a web page:
Uri webpage = Uri.parse("http://www.android.com"); Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);
Other kinds of implicit intents require "extra" data that provide different data types, such as a string. You can add one or more pieces of extra data using the various putExtra()
methods.
By default, the system determines the appropriate MIME type required by an intent based on the Uri
data that's included. If you don't include a Uri
in the intent, you should usually use setType()
to specify the type of data associated with the intent. Setting the MIME type further specifies which kinds of activities should receive the intent.
Here are some more intents that add extra data to specify the desired action:
- Send an email with an attachment:
Intent emailIntent = new Intent(Intent.ACTION_SEND); // The intent does not have a URI, so declare the "text/plain" MIME type emailIntent.setType(HTTP.PLAIN_TEXT_TYPE); emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] {"jon@example.com"}); // recipients emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Email subject"); emailIntent.putExtra(Intent.EXTRA_TEXT, "Email message text"); emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment")); // You can also attach multiple items by passing an ArrayList of Uris
- Create a calendar event:
Intent calendarIntent = new Intent(Intent.ACTION_INSERT, Events.CONTENT_URI); Calendar beginTime = Calendar.getInstance().set(2012, 0, 19, 7, 30); Calendar endTime = Calendar.getInstance().set(2012, 0, 19, 10, 30); calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis()); calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis()); calendarIntent.putExtra(Events.TITLE, "Ninja class"); calendarIntent.putExtra(Events.EVENT_LOCATION, "Secret dojo");
Note: This intent for a calendar event is supported only with API level 14 and higher.
Note: It's important that you define your Intent
to be as specific as possible. For example, if you want to display an image using the ACTION_VIEW
intent, you should specify a MIME type of image/*
.This prevents apps that can "view" other types of data (like a map app) from being triggered by the intent.
Verify There is an App to Receive the Intent
To verify there is an activity available that can respond to the intent, call queryIntentActivities()
to get a list of activities capable of handling your Intent
. If the returned List
is not empty, you can safely use the intent. For example:
PackageManager packageManager = getPackageManager()
;
List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
boolean isIntentSafe = activities.size() > 0;
If isIntentSafe
is true
, then at least one app will respond to the intent. If it is false
, then there aren't any apps to handle the intent.
Here's a complete example that shows how to create an intent to view a map, verify that an app exists to handle the intent, then start it:
// Build the intent
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);
// Verify it resolves
PackageManager packageManager = getPackageManager()
;
List<ResolveInfo> activities = packageManager.queryIntentActivities(mapIntent, 0);
boolean isIntentSafe = activities.size() > 0;
// Start an activity if it's safe
if (isIntentSafe) {
startActivity(mapIntent);
}
Show an App Chooser
- Even if the user has previously selected a default action for this intent, the chooser will still be displayed.
- If no applications match, Android displays a system message.
- You can specify a title for the chooser dialog.
To show the chooser, create an Intent
using createChooser()
and pass it tostartActivity()
. For example:
Intent intent = new Intent(Intent.ACTION_SEND); ... // Always use string resources for UI text. // This says something like "Share this photo with" String title = getResources().getString(R.string.chooser_title); // Create intent to show chooser Intent chooser = Intent.createChooser(intent, title); // Verify the intent will resolve to at least one activity if (intent.resolveActivity(getPackageManager()) != null) { startActivity(chooser); }
This displays a dialog with a list of apps that respond to the intent passed to the createChooser()
method and uses the supplied text as the dialog title.
Getting a Result from an Activity
startActivityForResult()
(instead of
startActivity()
).
Intent
object. Your activity receives it in the onActivityResult()
callback.startActivityForResult()
. Intent
, the callback provides the same request code so that your app can properly identify the result and determine how to handle it.For example, here's how to start an activity that allows the user to pick a contact:
static final int PICK_CONTACT_REQUEST = 1; // The request code ... private void pickContact() { Intent pickContactIntent = new Intent(Intent.ACTION_PICK, Uri.parse("content://contacts")); pickContactIntent.setType(Phone.CONTENT_TYPE); // Show user only contacts w/ phone numbers startActivityForResult(pickContactIntent, PICK_CONTACT_REQUEST); }
Receive the Result
When the user is done with the subsequent activity and returns, the system calls your activity'sonActivityResult()
method. This method includes three arguments:
- The request code you passed to
startActivityForResult()
. - A result code specified by the second activity. This is either
RESULT_OK
if the operation was successful orRESULT_CANCELED
if the user backed out or the operation failed for some reason. - An
Intent
that carries the result data.
For example, here's how you can handle the result for the "pick a contact" intent:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { // Check which request we're responding to if (requestCode == PICK_CONTACT_REQUEST) { // Make sure the request was successful if (resultCode == RESULT_OK) { // The user picked a contact. // The Intent's data Uri identifies which contact was selected. // Do something with the contact here (bigger example below) } } }
The code above showing how to get a result from the People app doesn't go into details about how to actually read the data from the result, because it requires more advanced discussion about content providers. However, if you're curious, here's some more code that shows how to query the result data to get the phone number from the selected contact:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// Check which request it is that we're responding to
if (requestCode == PICK_CONTACT_REQUEST) {
// Make sure the request was successful
if (resultCode == RESULT_OK) {
// Get the URI that points to the selected contact
Uri contactUri = data.getData();
// We only need the NUMBER column, because there will be only one row in the result
String[] projection = {Phone.NUMBER};
// Perform the query on the contact to get the NUMBER column
// We don't need a selection or sort order (there's only one result for the given URI)
// CAUTION: The query() method should be called from a separate thread to avoid blocking
// your app's UI thread. (For simplicity of the sample, this code doesn't do that.)
// Consider using CursorLoader
to perform the query.
Cursor cursor = getContentResolver()
.query(contactUri, projection, null, null, null);
cursor.moveToFirst();
// Retrieve the phone number from the NUMBER column
int column = cursor.getColumnIndex(Phone.NUMBER);
String number = cursor.getString(column);
// Do something with the phone number...
}
}
}
Allowing Other Apps to Start Your Activity
<intent-filter>
element in your manifest file for the corresponding
<activity>
element.
startActivity()
or startActivityForResult()
, with an implicit intent, the system finds which activity (or activities) can respond to the intent.In order to properly define which intents your activity can handle, eac h intent filter you add should be as specific as possible in terms of the type of action and data the activity accepts.
The system may send a given Intent
to an activity if that activity has an intent filter fulfills the following criteria of the Intent
object:
-
Action
-
A string naming the action to perform. Usually one of the platform-defined values such as
ACTION_SEND
orACTION_VIEW
.Specify this in your intent filter with the
<action>
element. The value you specify in this element must be the full string name for the action, instead of the API constant (see the examples below).
Data
-
A description of the data associated with the intent.
Specify this in your intent filter with the
<data>
element. Using one or more attributes in this element, you can specify just the MIME type, just a URI prefix, just a URI scheme, or a combination of these and others that indicate the data type accepted.Note: If you don't need to declare specifics about the data
Uri
(such as when your activity handles to other kind of "extra" data, instead of a URI), you should specify only theandroid:mimeType
attribute to declare the type of data your activity handles, such astext/plain
orimage/jpeg
.
Category
-
Provides an additional way to characterize the activity handling the intent, usually related to the user gesture or location from which it's started. There are several different categories supported by the system, but most are rarely used. However, all implicit intents are defined with
CATEGORY_DEFAULT
by default.Specify this in your intent filter with the
<category>
element.
In your intent filter, you can declare which criteria your activity accepts by declaring each of them with corresponding XML elements nested in the <intent-filter>
element.
For example, here's an activity with an intent filter that handles the ACTION_SEND
intent when the data type is either text or an image:
<activity android:name="ShareActivity"> <intent-filter> <action android:name="android.intent.action.SEND"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="text/plain"/> <data android:mimeType="image/*"/> </intent-filter> </activity>Each incoming intent specifies only one action and one data type, but it's OK to declare multiple instances of the
<action>
,
<category>
, and
<data>
elements in each
<intent-filter>
.
For example, suppose your activity handles both text and images for both the ACTION_SEND
and ACTION_SENDTO
intents. In this case, you must define two separate intent filters for the two actions because a ACTION_SENDTO
intent must use the data Uri
to specify the recipient's address using the send
or sendto
URI scheme. For example:
<activity android:name="ShareActivity"> <!-- filter for sending text; accepts SENDTO action with sms URI schemes --> <intent-filter> <action android:name="android.intent.action.SENDTO"/> <category android:name="android.intent.category.DEFAULT"/> <data android:scheme="sms" /> <data android:scheme="smsto" /> </intent-filter> <!-- filter for sending text or images; accepts SEND action and text or image data --> <intent-filter> <action android:name="android.intent.action.SEND"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="image/*"/> <data android:mimeType="text/plain"/> </intent-filter> </activity>
Note: In order to receive implicit intents, you must include the CATEGORY_DEFAULT
category in the intent filter. The methods startActivity()
and startActivityForResult()
treat all intents as if they declared theCATEGORY_DEFAULT
category. If you do not declare it in your intent filter, no implicit intents will resolve to your activity.
For more information about sending and receiving ACTION_SEND
intents that perform social sharing behaviors, see the lesson about Receiving Simple Data from Other Apps.
Handle the Intent in Your Activity
As your activity starts, call getIntent()
to retrieve the Intent
that started the activity. You can do so at any time during the lifecycle of the activity, but you should generally do so during early callbacks such as onCreate()
oronStart()
.
For example:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // Get the intent that started this activity Intent intent = getIntent(); Uri data = intent.getData(); // Figure out what to do based on the intent type if (intent.getType().indexOf("image/") != -1) { // Handle intents with image data ... } else if (intent.getType().equals("text/plain")) { // Handle intents with text ... } }
Return a Result
f you want to return a result to the activity that invoked yours, simply call setResult()
to specify the result code and result Intent
. When 1441 your operation is done and the user should return to the original activity, callfinish()
to close (and destroy) your activity. For example:
// Create intent to deliver some kind of result data Intent result = new Intent("com.example.RESULT_ACTION", Uri.parse("content://result_uri"); setResult(Activity.RESULT_OK, result); finish();
You must always specify a result code with the result. Generally, it's either RESULT_OK
or RESULT_CANCELED
. You can then provide additional data with an Intent
, as necessary.
RESULT_CANCELED
by default. So, if the user presses the Back button before completing the action and before you set the result, the original activity receives the "canceled" result.
If you simply need to return an integer that indicates one of several result options, you can set the result code to any value higher than 0. If you use the result code to deliver an integer and you have no need to include theIntent
, you can call setResult()
and pass only a result code. For example:
setResult(RESULT_COLOR_RED); finish();
- Even if the user has previously selected a default action for this intent, the chooser will still be displayed.
- If no applications match, Android displays a system message.
- You can specify a title for the chooser dialog.