Android之Intents 和Intent Filters


1. Intents 和Intent Filters

  • to start an Activity
    startActivity or startActivityForResults
  • to start a service
    startService or bindService
  • to deliever a broadcast
    sendBroadcast, sendOrderedBroadcast or sendStickyBroadcast

1.1 Intent Types

  • Explicit intents
    指定請求組件的全限定名,就包名+類名。
  • Implicit intents
    申明通用的動做去執行,容許其餘App處理該動做。

1.2 Building Intent

  • Component name
    是決定該Intent是否爲Explicit Intent,可經過set Component(), setClass(), setClassName(), 或者是做爲Intent()的構造器的參數。若沒指定該參數,則系統使用一下item進行匹配。其中Service必須指定Component Name。
  • Action
    是一個String字符串,指定通用動做去執行,如View or Pick。該字段一般可以決定Intent的其餘字段如何構造,尤爲是在data域和extras域。可自定義Action,但更推薦使用系統提供的。如下爲經常使用的Action, ACTION_VIEW(使用地圖顯示地址或使用相冊顯示圖片),ACTION_SEND(使用其餘App共享數據,諸如電子郵件或者社交網絡共享).
    能夠經過setAction(),或者Intent的構造器進行指定。定義本身的ACTION,請加上包名,以下
    static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";
  • Data
    使用URI指定MIME類型的數據,一般須要指定數據類型。可是使用content: URI的URI數據,可不指定類型,由於系統可識別出該數據位於設備上,而且受到ContentProvider控制,所以MIME類型就變爲可見。
    指定方式爲setData(), setType() or setDataAndType(),其中setData和setType不可同時使用,若須要,請使用setDataAndType()。
  • Category
    一個String,包含可處理該Intent的組件種類。每一個Intent可包含任意數量的Category,但大部分的Intent都不須要,一般設置爲android.intent.category.DEFAULT。常見的Category:CATEGORY_BROWSABLECATEGORY_LAUNCHER。前者表示該數據可爲瀏覽器打開,後者表示該Activity是一個任務的初始Activity,而且將會被顯示在Launcher裏。可用'addCategory()'來指定該項。
    >Tip 以上介紹的component name, action, data, 和category限定了一個intent的特性,Android系統可知道如何決定一個組件來處理或啓動。
  • Extras
    攜帶鍵值對信息,KV來完成特定的Action。可經過putExtras(K, V),或者建立一個Bundle攜帶全部的KVP,而後putExtras到Intent。指定本身的Extras Key,務必加上包名,如static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";
  • FLAG
    定義Intent的元素據metadata,可指導Android系統如何啓動一個Activity(task所屬),或者啓動後如何對待(是否屬於其餘已經啓動的Activity)

1.2 Examples

  • Explicit Intent
// Executed in an Activity, so 'this' is the Context
// The fileUrl is a string URL, such as "http://www.example.com/image.png"
Intent downloadIntent = new Intent(this, DownloadService.class);
downloadIntent.setData(Uri.parse(fileUrl));
startService(downloadIntent);
  • Implicit Intent
    模糊的Intent,可能會沒有App響應,致使App Crash。所以可經過resolveActitvity()來驗證是否有Activity響應,而後再決定是否啓動Activity。
// Create the text message with a string
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
sendIntent.setType(HTTP.PLAIN_TEXT_TYPE); // "text/plain" MIME type

// Verify that the intent will resolve to an activity
if (sendIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(sendIntent);
}

如有多個App響應,則顯示列表對話框以供用戶選擇,若是隻有一個App響應,則直接啓動。
- 強制出現App選擇器
如分享文件或者數據到各類App,ACTION_SEND。可以使用Intent的creatChooser來操做,以下:html

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 (sendIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(sendIntent);
}

1.3 Receiving an Implicit Intent

在Manifest文件中申明< intent-filters >標籤,經過action, data, and category等字段制定Intent可接受的類型。
一個Explicit Intent無視組件所申明的接受Intent類型,直接傳遞過去。
不一樣job應申明不一樣的< intent-filters >,可包括action, data, and category3個字段。
-action, 指定可接受的intetn action。
-data,可接受的數據類型,URI (scheme, host, port, path, etc.) and MIME type。
-category,必須是一個Action的string值。android

Tip: 爲了收到Implicit Intents,必須設定CATEGORY_DEFAULT。這樣, startActivity() and startActivityForResult() 纔可調用,不然沒有任何Implicit可啓動該Activity。算法

舉例:shell

<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"/>
    </intent-filter>
</activity>

只有三個item都經過驗證,Android纔會傳遞Intent給該Activity。對於Broadcast Receiver,可經過registerReceiver() or unregisterReceiver()動態綁定。
- Example Filters瀏覽器

<activity android:name="MainActivity">
    <!-- This activity is the main entry, should appear in app launcher -->
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

<activity android:name="ShareActivity">
    <!-- This activity handles "SEND" actions with text data -->
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="text/plain"/>
    </intent-filter>
    <!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data -->
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <action android:name="android.intent.action.SEND_MULTIPLE"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="application/vnd.google.panorama360+jpg"/>
        <data android:mimeType="image/*"/>
        <data android:mimeType="video/*"/>
    </intent-filter>
</activity>

1.4 Using a Pending Intent

它是對Intent的包裝器,主要用途是給予其餘App權限獲取本進程的數據。主要用途以下:網絡

  • Notification Manager
  • AppWidget
  • AlarmManager

因爲每一個Intent都是爲特定的組件設計的,所以PendingIntent也一樣。app

  • PendingIntent.getActivity(),啓動Activtiy
  • PendingIntent.getService(),啓動Service
  • PendingIntent.getBroadcast(), 啓動BroadcastReceiver()。

1.5 Intent Resolution

Android 系統匹配最優的組件的算法,基於如下三方面的匹配測試:ide

  • The intent action
  • The intent data (both URI and data type)
  • The intent category
    其中data的URI 結構和MIME 類型。
    URI:<scheme>://<host>:<port>/<path>
    ex:content://com.example.project:200/folder/subfolder/etc
    這4個元素是線性依賴的:
    >If a scheme is not specified, the host is ignored.
    If a host is not specified, the port is ignored.
    If both the scheme and host are not specified, the path is ignored.

PackageManager 能夠調用如下幾個方法列出可接受該Intent的組件post

  • queryIntentActivities(), 返回全部類似的Activity
  • queryIntentServices(),返回類似的全部Service
  • queryIntentBroadcastReceivers(), 返回全部

1.6 Common Intents

1 AlarmClock

Action: ACTION_SET_ALARM
Extras:....
ex:測試

public void createAlarm(String message, int hour, int minutes) {
    Intent intent = new Intent(AlarmClock.ACTION_SET_ALARM)
            .putExtra(AlarmClock.EXTRA_MESSAGE, message)
            .putExtra(AlarmClock.EXTRA_HOUR, hour)
            .putExtra(AlarmClock.EXTRA_MINUTES, minutes);
    if (intent.resolveActivity(getPackageManager()) != null) {
        startActivity(intent);
    }
}

並其須要使用權限:
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
相應的Intent-Filter

<activity ...>
    <intent-filter>
        <action android:name="android.intent.action.SET_ALARM" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

2 Timer

Action:ACTION_SET_TIMER
Extras:。。。
e.g.

public void startTimer(String message, int seconds) {
    Intent intent = new Intent(AlarmClock.ACTION_SET_TIMER)
            .putExtra(AlarmClock.EXTRA_MESSAGE, message)
            .putExtra(AlarmClock.EXTRA_LENGTH, seconds)
            .putExtra(AlarmClock.EXTRA_SKIP_UI, true);
    if (intent.resolveActivity(getPackageManager()) != null) {
        startActivity(intent);
    }
}

Permission:
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
Intent-Filter:

<activity ...>
    <intent-filter>
        <action android:name="android.intent.action.SET_TIMER" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

3 顯示全部Alarms

Action:ACTION_SHOW_ALARMS

4 添加Calendar Event

Action:ACTION_INSERT
Data URI:Events.CONTENT_URI
MIME Type: "vnd.android.cursor.dir/event"
Extras: 。。。

4 拍攝照片或攝製錄像

Action:ACTION_IMAGE_CAPTURE or ACTION_VIDEO_CAPTURE
Extras:EXTRA_OUTPUT
使用onActivityResult()接收返回數據:

static final int REQUEST_IMAGE_CAPTURE = 1;
static final Uri mLocationForPhotos;

public void capturePhoto(String targetFilename) {
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    intent.putExtra(MediaStore.EXTRA_OUTPUT,
            Uri.withAppendedPath(mLocationForPhotos, targetFilename);
    if (intent.resolveActivity(getPackageManager()) != null) {
        startActivityForResult(intent, REQUEST_IMAGE_CAPTURE);
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
        Bitmap thumbnail = data.getParcelable("data");
        // Do other work with full size photo saved in mLocationForPhotos
        ...
    }
}

相應的Intent-Filter

<activity ...>
    <intent-filter>
        <action android:name="android.media.action.IMAGE_CAPTURE" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

5 Start a camera app in still image mode

Action: INTENT_ACTION_STILL_IMAGE_CAMERA

6 Start a camera app in video mode

Action: INTENT_ACTION_VIDEO_CAMERA

7 選擇一個聯繫人

Action:ACTION_PICK
MIME Type:Contacts.CONTENT_TYPE
e.g.:

static final int REQUEST_SELECT_CONTACT = 1;

public void selectContact() {
    Intent intent = new Intent(Intent.ACTION_PICK);
    intent.setType(ContactsContract.Contacts.CONTENT_TYPE);
    if (intent.resolveActivity(getPackageManager()) != null) {
        startActivityForResult(intent, REQUEST_SELECT_CONTACT);
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == REQUEST_SELECT_CONTACT && resultCode == RESULT_OK) {
        Uri contactUri = data.getData();
        // Do something with the selected contact at contactUri
        ...
    }
}

8 選擇特定的聯繫人

Action: ACTION_PICK
MIME Type:
CommonDataKinds.Phone.CONTENT_TYPE。Pick from contacts with a phone number.
CommonDataKinds.Email.CONTENT_TYPE,Pick from contacts with an email address.
CommonDataKinds.StructuredPostal.CONTENT_TYPE,Pick from contacts with a postal address.

static final int REQUEST_SELECT_PHONE_NUMBER = 1;

public void selectContact() {
    // Start an activity for the user to pick a phone number from contacts
    Intent intent = new Intent(Intent.ACTION_PICK);
    intent.setType(CommonDataKinds.Phone.CONTENT_TYPE);
    if (intent.resolveActivity(getPackageManager()) != null) {
        startActivityForResult(intent, REQUEST_SELECT_PHONE_NUMBER);
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == REQUEST_SELECT_PHONE_NUMBER && resultCode == RESULT_OK) {
        // Get the URI and query the content provider for the phone number
        Uri contactUri = data.getData();
        String[] projection = new String[]{CommonDataKinds.Phone.NUMBER};
        Cursor cursor = getContentResolver().query(contactUri, projection,
                null, null, null);
        // If the cursor returned is valid, get the phone number
        if (cursor != null && cursor.moveToFirst()) {
            int numberIndex = cursor.getColumnIndex(CommonDataKinds.Phone.NUMBER);
            String number = cursor.getString(numberIndex);
            // Do something with the phone number
            ...
        }
    }
}

9 顯示一個聯繫人

  • ACTION_PICK返回的contactURI,而後使用ACTION_VIEW查看。
  • 直接訪問聯繫人列表,須要READ_CONTACTS權限
public void viewContact(Uri contactUri) {
    Intent intent = new Intent(Intent.ACTION_VIEW, contactUri);
    if (intent.resolveActivity(getPackageManager()) != null) {
        startActivity(intent);
    }
}

10 編輯一個聯繫人

Action:ACTION_EDIT
URI: 以前ACTION_PICK返回的contactURI。
Extras:ContactsContract.Intents.Insert中定義的條目均可編輯

public void editContact(Uri contactUri, String email) {
    Intent intent = new Intent(Intent.ACTION_EDIT);
    intent.setData(contactUri);
    intent.putExtra(Intents.Insert.EMAIL, email);
    if (intent.resolveActivity(getPackageManager()) != null) {
        startActivity(intent);
    }
}

11 插入一個聯繫人

Action:ACTION_INSERT
MIME Type:Contacts.CONTENT_TYPE
Extras:One or more of the extras defined in ContactsContract.Intents.Insert.
e.g.:

public void insertContact(String name, String email) {
    Intent intent = new Intent(Intent.ACTION_INSERT);
    intent.setType(Contacts.CONTENT_TYPE);
    intent.putExtra(Intents.Insert.NAME, name);
    intent.putExtra(Intents.Insert.EMAIL, email);
    if (intent.resolveActivity(getPackageManager()) != null) {
        startActivity(intent);
    }
}

12 Email

13 File Storage

14 Fitness

15 Local Actions

16 Maps, show a location on a map

Action: ACTION_VIEW
URI: geo:latitude,longtitude
e.g.:

public void showMap(Uri geoLocation) {
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setData(geoLocation);
    if (intent.resolveActivity(getPackageManager()) != null) {
        startActivity(intent);
    }
}

intent filter:

<activity ...>
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <data android:scheme="geo" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

17 MUSIC or VIDEO

Action: ACTION_VIEW
Data URI Scheme:

  • file:
  • content:
  • http:

MIME Type:

  • "audio/*"
  • "application/ogg"
  • "application/x-ogg"
  • "application/itunes" Or any other that your app may require.

example intent filter:

<activity ...>
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <data android:type="audio/*" />
        <data android:type="application/ogg" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

18 Phone

Action: ACTION_DIAL , ACTION_CALL
其中ACTION_DIAL,須要傳輸一個號碼,而後跳轉到撥打界面,須要點擊撥打按鈕。
而ACTION_CALL,須要傳輸一個號碼,而後直接開始撥打,可是須要權限
<uses-permission android:name="android.permission.CALL_PHONE" />
Data URI Scheme:'tel:< phone-number>,voicemail:< phone-number>'
e.g.:

public void dialPhoneNumber(String phoneNumber) {
    Intent intent = new Intent(Intent.ACTION_DIAL);
    intent.setData(Uri.parse("tel:" + phoneNumber));
    if (intent.resolveActivity(getPackageManager()) != null) {
        startActivity(intent);
    }
}

19 Settings

Action:

  • ACTION_SETTINGS ACTION_WIRELESS_SETTINGS
  • ACTION_AIRPLANE_MODE_SETTINGS ACTION_WIFI_SETTINGS
  • ACTION_APN_SETTINGS ACTION_BLUETOOTH_SETTINGS ACTION_DATE_SETTINGS
  • ACTION_LOCALE_SETTINGS ACTION_INPUT_METHOD_SETTINGS
  • ACTION_DISPLAY_SETTINGS ACTION_SECURITY_SETTINGS
  • ACTION_LOCATION_SOURCE_SETTINGS ACTION_INTERNAL_STORAGE_SETTINGS
  • ACTION_MEMORY_CARD_SETTINGS

20 Text Messaging

Action: ACTION_SENDTO, ACTION_SEND, ACTION_SEND_MULTIPLE
Data URI Scheme:

sms:<phone_number>
smsto:<phone_number>
mms:<phone_number>
mmsto:<phone_number>

MIME Type:
PLAIN_TEXT_TYPE ("text/plain")
"image/"
"video/
"
Extras:
"subject",'sms_body','EXTRA_STREAM'

e.g.:

public void composeMmsMessage(String message, Uri attachment) {
    Intent intent = new Intent(Intent.ACTION_SENDTO);
    intent.setType(HTTP.PLAIN_TEXT_TYPE);
    intent.putExtra("sms_body", message);
    intent.putExtra(Intent.EXTRA_STREAM, attachment);
    if (intent.resolveActivity(getPackageManager()) != null) {
        startActivity(intent);
    }
}

若想要確保intent被短信應用處理,使用 ACTION_SENDTO,而且設置data schmem爲‘smsto:’.
相應的Intent-filter

<activity ...>
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <data android:type="text/plain" />
        <data android:type="image/*" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

21. WebBrowser

加載網址
- Action: ACTION_VIEW
- Data URI Scheme:
http:< URL>
https:< URL>
- MIME Type:
PLAIN_TEXT_TYPE ("text/plain")
"text/html"
"application/xhtml+xml"
"application/vnd.wap.xhtml+xml"

Web查詢
Action: ACTION_WEB_SEARCH
Extras:SearchManager.QUERY The search string.

public void searchWeb(String query) {
    Intent intent = new Intent(Intent.ACTION_SEARCH);
    intent.putExtra(SearchManager.QUERY, query);
    if (intent.resolveActivity(getPackageManager()) != null) {
        startActivity(intent);
    }
}

22 Verify Intents with the Android Debug Bridge

  1. Set up an Android device for development, or use a virtual device.
  2. Install a version of your app that handles the intents you want to support.
  3. Fire an intent using adb:
    adb shell am start -a <ACTION> -t <MIME_TYPE> -d <DATA> \ -e <EXTRA_NAME> <EXTRA_VALUE> -n <ACTIVITY>
    For example:
    adb shell am start -a android.intent.action.DIAL \ -d tel:555-5555 -n org.example.MyApp/.MyActivity If you defined the required intent filters, your app should handle the intent.
相關文章
相關標籤/搜索