Android Intent過濾器
Android Intent 是承載一個意圖,即對象。將消息從一個組件傳到另一個組件,在應用程序或應用程序之外。Intent 之間溝通信息的任何應用程序的三個核心組件 - 活動,服務和廣播接收器。
意圖本身是一個Intent對象,是一種被動的數據結構保持將要執行的動作的抽象描述。
例如,讓我們假設有一個Activity ,需要啟動電子郵件客戶端和發送電子郵件,使用Android設備。為了達到這個目的,Activity會隨著適當選擇器,一個ACTION_SEND發送到 Android Intent 解析器。指定的選擇器提供適當的接口供用戶選擇如何發送電子郵件數據。
例如,有一個Activity ,需要在 Android 設備上用Web瀏覽器打開網址。為了達到這個目的Activity將發送ACTION_WEB_SEARCH Intent 到Android Intent 解析器,並在Web瀏覽器中打開給定的URL。Intent 解析器解析通過一個活動列表,並選擇一個最合適的 Intent ,在這種情況下,就是Web瀏覽器活動。Intent通過網頁解析後,網頁瀏覽器啟動 Web 瀏覽器活動。
分開機製對於每種類型的組件提供意圖,如:活動,服務和廣播接收器。
S.N. | 方法& 描述 |
---|---|
1 |
Context.startActivity() Intent對象傳遞給此方法來啟動一個新的活動或獲得現有活動來做一些新的東西。 |
2 |
Context.startService() Intent對象傳遞給此方法來啟動服務或提供新的指令到一個持續的服務。 |
3 |
Context.sendBroadcast() Intent對象傳遞給這個方法消息給所有感興趣的廣播接收器。 |
Intent對象
Intent對象是成捆的信息,這些信息所使用的組件,它接收的意圖和Android係統中的信息。
Intent對象可以基於它是什麼交流或要執行,包含以下組件:
動作
強製Intent對象是一個字符串,命名要執行操作或廣播意圖,正在發生的動作和報告。動作在很大程度上決定意圖對象的其餘部分的結構如何。Intent類定義了一些動作常數對應不同的意圖。下麵列出的是 Android Intent標準動作
動作在一個Intent對象的 setAction() 方法可以設置,通過 getAction() 方法讀取。
數據
要采取動作的數據的URI和該數據的MIME類型。例如,如果動作字段ACTION_EDIT,在數據字段將包含要顯示的編輯的文檔的URI。
setData()方法指定數據僅作為URI的setType()指定它隻能作為一個MIME類型,和setDataAndType()指定它作為一個URI和MIME類型。讀取的URI由getData()和getType()。
操作/數據對的一些例子是:
S.N. | 動作/數據對和說明 |
---|---|
1 |
ACTION_VIEW content://contacts/people/1 顯示有關其標識符為“1”的人的信息。 |
2 |
ACTION_DIAL content://contacts/people/1 顯示電話撥號程序已填充的人。 |
3 |
ACTION_VIEW tel:123 顯示電話撥號程序已填充的給定數。 |
4 |
ACTION_DIAL tel:123 顯示電話撥號程序已填充的給定數。 |
5 |
ACTION_EDIT content://contacts/people/1 編輯有關其標識符為“1”的人的信息。 |
6 |
ACTION_VIEW content://contacts/people/ 顯示人的列表,用戶可以瀏覽。 |
類彆
類彆是 Intent 對象一個可選部分,這是一個字符串,其中包含應該處理這個 Intent 組件的附加信息。 addCategory()方法將類彆添加到 Intent對象,removeCategory() 刪除一個類彆,GetCategories() 得到當前在對象的所有類彆集合。下麵是 Android意圖標準類彆 列表。
要查看詳細的 Intent過濾器可在下一小節,了解如何使用類彆,選擇合適的活動對應的意圖。
附加設備
這是鍵-值對,可了解更多傳遞組件處理 intent 的信息。額外內容設置和讀取使用 putExtras() 和 getExtras() 方法。這裡是一個 Android intent 標準額外數據列表。
標誌位
這些標誌是Intent對象可選部分,並指示Android係統如何啟動一個活動以及如何對待它在啟動後等等。
組件名稱
可選字段是一個 android 組件名稱的活動,服務或BroadcastReceiver類對象。如果它冇有被設置,Android使用Intent 對象的信息,找到一個合適的目標,Intent 對象傳遞到指定類的一個實例。
組件名稱由setComponent(),setClass()設置,由 setClassName()和 getComponent()讀取。
Intents類型
有以下兩種類型的意圖支持到 Android 4.1版本
顯式意圖
顯示意圖指定目標組件的名稱,通常用於應用程序內部消息 - 比如一個活動啟動從服務或啟動一個組活動。例如:
// Explicit Intent by specifying its class name Intent i = new Intent(this, TargetActivity.class); i.putExtra("Key1", "ABC"); i.putExtra("Key2", "123"); // Starts TargetActivity startActivity(i);
隱式意圖
這些意圖由其的名字指定目標組件,它們通常用於應用程序內部消息 - 例如一個活動啟動一個附屬服務或啟動一個姐妹的活動。例如:
// Implicit Intent by specifying a URI Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.example.com")); // Starts Implicit Activity startActivity(i);
目標組件接收的意圖可以使用getExtras()方法來獲得組件發送額外的數據源。例如:
// Get bundle object at appropriate place in your code Bundle extras = getIntent().getExtras(); // Extract data using passed keys String value1 = extras.getString("Key1"); String value2 = extras.getString("Key2");
例子
下麵的例子展示了Android意圖的功能,啟動各種 Android 的內置應用。
步驟 | 描述 |
---|---|
1 | 使用Eclipse IDE創建Android應用程序,並將其命名為IntentDemo在com.example.intentdemo包下。在創建這個項目,請確保目標SDK並編譯在Android SDK的最新版本為使用更高級彆的API。 |
2 | 修改 src/MainActivity.java 文件,並添加代碼來定義相應的兩個按鈕,即兩個監聽器。啟動瀏覽器,並打開電話。 |
3 | 修改布局XML文件res/layout/activity_main.xml添加三個按鈕的設置為線性布局。 |
4 | 修改 res/values/strings.xml 中定義所需的常量值 |
5 | 運行該應用程序啟動Android模擬器來驗證應用程序所做的修改結果。 |
以下是修改主要活動文件 src/com.example.intentdemo/MainActivity.java 的內容:
package com.example.intentdemo; import android.net.Uri; import android.os.Bundle; import android.app.Activity; import android.content.Intent; import android.view.Menu; import android.view.View; import android.widget.Button; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button startBrowser = (Button) findViewById(R.id.start_browser); startBrowser.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { Intent i = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse("http://www.example.com")); startActivity(i); } }); Button startPhone = (Button) findViewById(R.id.start_phone); startPhone.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { Intent i = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse("tel:9510300000")); startActivity(i); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action // bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } }
下麵是 res/layout/activity_main.xml 文件的內容:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <Button android:id="@+id/start_browser" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/start_browser"/> <Button android:id="@+id/start_phone" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/start_phone" /> </LinearLayout>
下麵 res/values/strings.xm 定義兩個新的常量的內容:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">IntentDemo</string> <string name="action_settings">Settings</string> <string name="hello_world">Hello world!</string> <string name="start_browser">Start Browser</string> <string name="start_phone">Start Phone</string> </resources>
以下是 AndroidManifest.xml 文件的默認內容:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.intentdemo" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.example.intentdemo.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
現在運行 IntentDemo應用程序。假設創建AVD同時做正確的環境設置。要從Eclipse運行的應用程序,打開一個項目的活動文件,並 從工具欄上單擊“Run” 圖標。 Eclipse AVD安裝的應用程序,並啟動它,如果一切都設置和應用冇有問題,它會顯示以下模擬器窗口:
現在點擊開始瀏覽按鈕,這將啟動一個瀏覽器配置並顯示 http://www.example.com 如下所示:
類似的方式,可以啟動手機界麵使用開始電話按鈕,這允許撥打已經給定的電話號碼。
Intent過濾器
上麵已經看到了意圖如何用來調用一個活動。 Android操作係統使用過濾器來查明活動,服務和廣播接收器能夠處理指定的一組動作,類彆。使用 <intent-filter> 元素在 manifest 文件中,列出了動作,類彆和數據類型相關聯的活動,服務或廣播接收器。
以下是 AndroidManifest.xml 文件中的一部分,指定活動 com.example.intentdemo.CustomActivity 的兩個動作,類和數據,下麵是可以調用的一個例子:
<activity android:name=".CustomActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <action android:name="com.example.intentdemo.LAUNCH" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="http" /> </intent-filter> </activity>
活動的定義是隨著上麵提到的過濾器,活動將使用 android.intent.action.VIEW 或 com.example.intentdemo.LAUNCH 動作提供其類彆來調用這個活動,否則使用android.intent.category.DEFAULT。
<data> 元素活動被稱為指定數據類型,上麵的例子中自定義活動的數據以 "http://" 開始
有可能在隻是一個意圖的情況下,可以通過一個以上的活動或服務的過濾器,用戶可能會被要求指定激活哪個組件。可以發現如果冇有指定目標,則會引發異常。
以下測試 Android 檢查在調用活動前:
-
如上圖所示,但這個列表不能為空,可能會列出多個過濾器<intent-filter>動作,一個過濾器必須至少包含一個<action>元素,否則會阻止所有意圖。如果有一個以上的動作列出,那麼Android將嘗試匹配在調用活動之前所提到的其中一個動作。
-
過濾器<intent-filter>可能列出零個,一個或一個以上。如果冇有類被提到,Android也能通過這個測試,但如果超過一個類提到通過類的測試意圖,在過濾器中,每一個類中的Intent對象必須符合一個類。
-
每個<data>元素可以指定一個URI和數據類型(MIME媒體類型)。單獨的屬性,如方案,主機,端口和路徑URI的每個部分。同時包含URI和數據類型的一個Intent對象通過測試,隻有當它的類型在過濾器列出的類型相匹配數據類型的一部分。
例子
下麵是修改上麵例子的一個例子。在這裡將看到 Android 如何解決衝突,如果一個意圖調用定義了兩個活動,接下來如何調用自定義活動使用一個過濾器,第三個是一個在例外情況下,如果 Android 不提交適當的活動意圖定義。
步驟 | 描述 |
---|---|
1 | 使用Eclipse IDE創建 Android 應用程序,並將其命名為 IntentDemo 在一個包com.example.intentdemo下。在創建這個項目前,確保目標SDK編譯在Android SDK的最新版本或使用更高級彆的API。 |
2 | 修改 src/MainActivity.java 文件,並添加代碼來定義相應的布局文件中定義了三個按鈕的監聽器。 |
3 | 添加一個新的 src/CustomActivity.java 文件,將由不同的意圖來調用一個自定義的活動。 |
4 | 修改布局XML文件res/layout/activity_main.xml 添加三個按鈕的線性布局。 |
5 | 添加一個布局XML文件res/layout/custom_view.xml,在其中添加一個簡單的<TextView>來顯示通過意圖傳遞的數據。 |
6 | 修改 res/values/strings.xml 定義所需的常量值 |
7 | 修改 AndroidManifest.xml 添加 <intent-filter> 定義規則,來自定義意圖調用活動。 |
8 | 運行該應用程序啟動Android模擬器,並確認在應用修改變化的結果。 |
以下是內容是修改了主要活動文件 src/com.example.intentdemo/MainActivity.java.
package com.example.intentdemo; import android.net.Uri; import android.os.Bundle; import android.app.Activity; import android.content.Intent; import android.view.Menu; import android.view.View; import android.widget.Button; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // First intent to use ACTION_VIEW action with correct data Button startBrowser_a = (Button) findViewById(R.id.start_browser_a); startBrowser_a.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { Intent i = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse("http://www.example.com")); startActivity(i); } }); // Second intent to use LAUNCH action with correct data Button startBrowser_b = (Button) findViewById(R.id.start_browser_b); startBrowser_b.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { Intent i = new Intent("com.example.intentdemo.LAUNCH", Uri.parse("http://www.example.com")); startActivity(i); } }); // Third intent to use LAUNCH action with incorrect data Button startBrowser_c = (Button) findViewById(R.id.start_browser_c); startBrowser_c.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { Intent i = new Intent("com.example.intentdemo.LAUNCH", Uri.parse("https://www.example.com")); startActivity(i); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the // action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } }
以下是修改的主要活動文件的內容 src/com.example.intentdemo/CustomActivity.java.
package com.example.intentdemo; import android.app.Activity; import android.net.Uri; import android.os.Bundle; import android.widget.TextView; public class CustomActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.custom_view); TextView label = (TextView) findViewById(R.id.show_data); Uri url = getIntent().getData(); label.setText(url.toString()); } }
以下是 res/layout/activity_main.xml 文件的內容:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <Button android:id="@+id/start_browser_a" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/start_browser_a"/> <Button android:id="@+id/start_browser_b" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/start_browser_b"/> <Button android:id="@+id/start_browser_c" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/start_browser_c"/> </LinearLayout>
下麵是 res/layout/custom_view.xml 文件的內容:
<?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/show_data" android:layout_width="fill_parent" android:layout_height="400dp"/> </LinearLayout>
下麵 res/values/strings.xml 文件內容中定義兩個新的常量:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">IntentDemo</string> <string name="action_settings">Settings</string> <string name="hello_world">Hello world!</string> <string name="start_browser_a">Start Browser with VIEW action</string> <string name="start_browser_b">Start Browser with LAUNCH action</string> <string name="start_browser_c">Exception Condition</string> </resources>
以下是 AndroidManifest.xml 文件的默認內容:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.intentdemo" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.example.intentdemo.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="com.example.intentdemo.CustomActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <action android:name="com.example.intentdemo.LAUNCH" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="http" /> </intent-filter> </activity> </application> </manifest>
要運行IntentDemo應用程序。假設創建了AVD並設置了環境。要從 Eclipse 運行應用程序,打開一個項目的活動文件,從工具欄上單擊“Run” 圖標。 Eclipse AVD安裝的應用程序並啟動它,如果一切設置和應用都冇有問題,它會顯示以下模擬器窗口:
現在,開始第一個按鈕“Start Browser with VIEW Action”。這裡定義了自定義活動過濾器“android.intent.action.VIEW”,並且已經有一個默認的活動,由Android啟動Web瀏覽器視圖定義動作,所以android 顯示以下兩個選項來選擇要啟動的活動。
現在,如果選擇瀏覽器,那麼Android將啟動網頁瀏覽器並打開 example.com 網站,但如果選擇“IndentDemo”選項,那麼Android將啟動CustomActivity什麼也不做,隻不過是捕捉傳遞的數據,並顯示在文本視圖如下:
現在使用“後退”按鈕,並點擊“Start Browser with LAUNCH Action”按鈕,這裡 Android 應用過濾器來選擇定義活動,隻需啟動自定義活動,再次顯示以下畫麵:
同樣,返回使用“後退”按鈕,並點擊“Exception Condition”按鈕,在這裡Android試圖找出一個有效的過濾器,對於給定intent,它冇有找到一個有效活動定義,因為在這個時候,已經數據使用HTTPS,而不是HTTP,雖然是一個正確的動作,但是Android拋出一個異常,並顯示以下畫麵: