一個Android App 通常會有多個Activity。每個Activity的界面都扮演者用戶入口的角色,允許用戶執行一些特定的任務(例如:查看地圖或者拍照等)。為了讓用戶能夠從一個Activity跳轉到另一個Activity,必須使用Intent來定義自己的意圖。
使用Intent實現與其他App執行的交互,比如:啟動另一個App,從其他App接收數據,以及使我們自己的App響應其他App發出的Intent。

主題一:將用戶傳送到另外一個App
比如:在一個應用中,用戶想要接收“本地”應用的數據,並顯示出指定數據的地理位置信息;這個時候並不適合在本地的Activity中創建地圖數據,而是使用Intent跳轉到其他的應用,比如:Map 應用。
Intent有兩種:顯式的和隱式的
相對於顯式Intent,隱式Intent能夠攜帶有指定的意圖信息,並跳轉到其他App中。how to create an implicit intent for a particular action, and how to use it to start an activity that performs the action in another app.
如何創建隱式Intent?
顯然,如果想要使用到顯式Intent,必須要知道對應的類名、Action名等信息。Implicit intents do not declare the class name of the component to start, but instead declare an action to perform.
包含有URI的Intent實例:If your data is a Uri, there's a simple Intent() constructor you can use define the action and data.
舉一個栗子:
打電話:
Uri number = Uri.parse("tel:5551234");
Intent callIntent = new Intent(Intent.ACTION_DIAL, number);
顯示地圖:
// 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);
瀏覽網頁:
Uri webpage = Uri.parse("http://www.android.com");
Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);
發送郵件:
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
創建日歷事件:
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: It's important
that you define your Intent to be as specific as possible.
驗證是否有App接收這個Intent
Although the Android platform guarantees that certain intents will resolve to one of the built-in apps (such as the Phone
, Email, or Calendar app), you should always include a verification step before invoking an intent. 在發送一個Intent之前,有必要驗證是否有App能夠接收該Intent。
必須注意的是:Caution: If you invoke an intent and there is no app available on the device that can handle the intent, your app will crash.
PackageManager packageManager = getPackageManager(); List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0); boolean isIntentSafe = activities.size() > 0;
如果返回的activities集合長度不為0,即不為空時,表示存在Activity能夠響應該Intent。
如何啟動另一個Activity?
startActivity(intent);
從一個Activity跳轉到另一個Activity的方式,系統會分析能夠響應該Intent的App。

並以Dialog的形式顯示出來。
下述示例程序能夠啟動地圖瀏覽功能:
// 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);
}
假若有多個App能夠響應指定的Intent,如何選擇?若每次的選擇都不確定,這種情況如何處理?
顯示選擇界面,供用戶決策

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);
}
主題二:獲取Activity的返回數據
Starting another activity doesn't have to be one-way. You can also start another activity and receive a result back. To receive a result, call startActivityForResult() (instead of startActivity()).
具體實現:When it does, it sends the result as another Intent object. Your activity receives it in the onActivityResult() callback. 返回Result時,仍然使用Intent。
Note: You can use explicit or implicit intents when you call startActivityForResult(). When starting one of your own activities to receive a result, you should use an explicit intent to ensure that you receive the expected result. 如果啟動自己App的Activity並期望返回結果時,建議使用顯式Intent,以確保接收期望的結果。
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);
}
The request code 意味:請求碼,用於標識當次請求。When you receive the result Intent, the callback provides the same request code so that your app can properly identify the result and determine how to handle it. 結果返回時,Intent會附帶有相同的請求碼,以確保請求的正確性。
其中在另一個Activity中會對返回的Intent附加數據:result code
A result code specified by the second activity. This is either RESULT_OK if the operation was successful or RESULT_CANCELED if the user backed out or the operation failed for some reason.
result code 用於標識對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)
}
}
}
舉個栗子:如何讀取聯系人信息
@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...
}
}
}
主題三:允許其他App啟動自己的Activity
即:讓自己的App響應其他App的Intent。
To allow other apps to start your activity, you need to add an <intent-filter> element in your manifest file for the corresponding <activity> element.
當app被安裝到設備上時,系統可以識別intent filter並把這些信息記錄下來。當其他app使用implicit intent執行 startActivity() 或者 startActivityForResult()時,系統會自動查找出那些可以響應該intent的Activity。
如何增加<intent-filter>?
為了盡可能確切的定義activity能夠handle的intent,每一個intent filter都應該盡可能詳盡的定義好action與data。
如果一個Activity的<intent-filter>具備以下特征,那么就是比較完善的:
Action:A string naming the action to perform. Usually one of the platform-defined values such as ACTION_SEND or ACTION_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.
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.
舉個栗子:
<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>
每一個發送出來的intent只會包含一個action與data類型,但handle這個intent的activity的 <intent-filter>可以聲明多個<action>, <category>與<data> 。
如果任何的兩對action與data是互相矛盾的,就應該創建不同的intent filter來指定特定的action與type。
<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 the CATEGORY_DEFAULT category. If you do not declare it in your intent filter, no implicit intents will resolve to your activity. 為了接受implicit intents, 必須在我們的intent filter中包含 CATEGORY_DEFAULT 的category。startActivity()和startActivityForResult()方法將所有intent視為聲明了CATEGORY_DEFAULT category。如果沒有在的intent filter中聲明CATEGORY_DEFAULT,activity將無法對implicit intent做出響應。
響應Intent,那如何獲取該Intent呢?
最好是在onCreate()和onStart()中獲取該Intent。
@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 ...
}
}
如何返回結果?
// 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();
在返回結果的Activity端,需要設置result code。Generally, it's either RESULT_OK or RESULT_CANCELED.
Note: The result is set to 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.
