Android Training(四):使用 Intent 與其他應用交互

一. Getting Started

1.5 Interacting with Other Apps

Android 應用一般具有若干個Activity明郭。每個 Activity 顯示一個用戶界面,用戶可通過該界面執(zhí)行特定任務(比如,查看地圖或拍照)。要將用戶從一個 Activity 轉至另一 Activity,您的應用必須使用 Intent 定義您的應用做某事的 “Intent”。

1.5.1 Sending the User to Another App

構建隱式 Intent


  • 使用指定電話號碼的 Uri 數據創(chuàng)建發(fā)起電話呼叫的 Intent:
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);
  • 發(fā)送帶附件的電子郵件:
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
  • 創(chuàng)建日歷事件:
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");

注:只有 API 級別 14 或更高級別支持此日歷事件 Intent。

驗證是否存在接收 Intent 的應用


調用 queryIntentActivities() 來獲取是否有能處理該 Intent 的 Activity 列表班缰。如果返回的 List 不為空,可以安全使用該 Intent悼枢。

PackageManager packageManager = getPackageManager();
List activities = packageManager.queryIntentActivities(intent,
        PackageManager.MATCH_DEFAULT_ONLY);
boolean isIntentSafe = activities.size() > 0;

啟動具有 Intent 的 Activity

此處顯示完整的示例:如何創(chuàng)建查看地圖的 Intent埠忘,驗證是否存在處理 Intent 的應用,然后啟動它:

// 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);
}

顯示應用選擇器


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);
}

1.5.2 startActivityForResult

啟動 Activity


例如,此處顯示如何開始允許用戶選擇聯(lián)系人的 Activity:

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);
}

接收結果


Activity 返回結果時會調用 onActivityResult() 方法莹妒,該方法有三個參數:

  • requestCode:請求碼名船,作為標記;
  • resultCode:結果碼旨怠,如果操作成功返回 RESULT_OK渠驼,失敗則 RESULT_CANCELED
  • data:傳送數據的 Intent 對象鉴腻。

本例說明您可以如何處理“選擇聯(lián)系人” 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)
        }
    }
}

成功獲取聯(lián)系人數據后的進一步操作:

@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...
        }
    }
}

注意讀取聯(lián)系人需要申請相應權限

1.5.2 Allowing Other Apps to Start Your Activity

要允許其他應用啟動您的 Activity,您需要在清單文件中為對應的 <activity> 元素添加一個 <intent-filter> 元素爽哎。

當您的應用安裝在設備上時蜓席,系統(tǒng)會識別您的 Intent 過濾器并添加信息至所有已安裝應用支持的 Intent 內部目錄。當應用通過隱含 Intent 調用 startActivity()startActivityForResult() 時倦青,系統(tǒng)會找到可以響應該 Intent 的 Activity。

添加 Intent 過濾器


Activity 基本 Intent 過濾器:

  • 操作 <action> 標簽:表示要執(zhí)行的操作名盹舞,如 ACTION_SENDACTION_VIEW产镐。
  • 數據 <data> 標簽:與 Intent 關聯(lián)的數據描述√卟剑可以指定 MIME 類型癣亚、URI 前綴、URI 架構或這些的組合以及其他指示所接受數據類型的項获印。

:如果您無需聲明關于數據的具體信息 Uri 比如述雾,您的 Activity 處理其他類型的“額外”數據而不是 URI 時),您應只指定 android:mimeType 屬性聲明您的 Activity 處理的數據類型兼丰,比如 text/plainimage/jpeg玻孟。

  • 類別:<category> 標簽:提供另外一種表征處理 Intent 的 Activity 的方法,通常與用戶手勢或 Activity 啟動的位置有關鳍征。 經常使用默認的 CATEGORY_DEFAULT 進行定義黍翎。

聲明 Activity 的 Intent 過濾器的各項屬性,比如下方的一個接收收據類型為文本或圖像時啟動的 Activity:

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

如果某 Activity 想要支持兩種不同的隱式 Intent 調用艳丛,需要再配置一個 Intent-filter 過濾器匣掸。

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

:為了接收隱含 Intent,您必須在 Intent 過濾器中包含 CATEGORY_DEFAULT 類別氮双。方法 startActivity()startActivityForResult() 將按照已聲明 CATEGORY_DEFAULT 類別的方式處理所有 Intent碰酝。如果您不在 Intent 過濾器中聲明它,則沒有隱含 Intent 分解為您的 Activity戴差。

處理您的 Activity 中的 Intent


在 onCreate() 中獲取傳遞來的 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 ...
    }
}

返回結果


使用 setResult() 方法和要返回的 Intent 對象來指定代碼和結果。

// 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();

:默認情況下,結果設置為 RESULT_CANCELED碱璃。因此弄痹,如果用戶在完成操作動作或設置結果之前按了返回按鈕,原始 Activity 會收到“已取消”的結果嵌器。

如果只需要返回某個整數肛真,可以使用以下方法:

setResult(RESULT_COLOR_RED);
finish();

1.6 Working with System Permissions

請求需要的權限


// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
                Manifest.permission.READ_CONTACTS)
        != PackageManager.PERMISSION_GRANTED) {

    // Should we show an explanation?
    if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
            Manifest.permission.READ_CONTACTS)) {

        // Show an expanation to the user *asynchronously* -- don't block
        // this thread waiting for the user's response! After the user
        // sees the explanation, try again to request the permission.

    } else {

        // No explanation needed, we can request the permission.

        ActivityCompat.requestPermissions(thisActivity,
                new String[]{Manifest.permission.READ_CONTACTS},
                MY_PERMISSIONS_REQUEST_READ_CONTACTS);

        // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
        // app-defined int constant. The callback method gets the
        // result of the request.
    }
}

處理權限請求響應


@Override
public void onRequestPermissionsResult(int requestCode,
        String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // permission was granted, yay! Do the
                // contacts-related task you need to do.

            } else {

                // permission denied, boo! Disable the
                // functionality that depends on this permission.
            }
            return;
        }

        // other 'case' lines to check for other
        // permissions this app might request
    }
}

在此分享一種權限申請寫法:

  1. 首先定義一個權限申請成功或失敗的回調接口:
private interface PermissionCallback
{
    void onSuccess();
    void onFailure();
}
  1. 下面代碼以申請攝像機權限舉例,如果需要申請更多權限除了要在 manifest 文件中添加爽航,也需要在 String[] 字符串數組中添加:
@TargetApi(23)
private void requestCameraPermission(PermissionCallback callback)
{
    if (Build.VERSION.SDK_INT >= 23) {
        if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            int requestCode = permissionRequestCodeSerial;
            permissionRequestCodeSerial += 1;
            permissionCallbacks.put(requestCode, callback);
            requestPermissions(new String[]{Manifest.permission.CAMERA}, requestCode);
        } else {
            callback.onSuccess();
        }
    } else {
        callback.onSuccess();
    }
}
  1. 權限申請回調蚓让,同時回調自定義接口:
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
{
    if (permissionCallbacks.containsKey(requestCode)) {
        PermissionCallback callback = permissionCallbacks.get(requestCode);
        permissionCallbacks.remove(requestCode);
        boolean executed = false;
        for (int result : grantResults) {
            if (result != PackageManager.PERMISSION_GRANTED) {
                executed = true;
                callback.onFailure();
            }
        }
        if (!executed) {
            callback.onSuccess();
        }
    }
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
  1. 使用時在相關 Activity 或 app 初始化時調用第 2 步中的方法:
requestCameraPermission(new PermissionCallback() {
    @Override
    public void onSuccess() {
    }

    @Override
    public void onFailure() {
    }
});
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市讥珍,隨后出現(xiàn)的幾起案子历极,更是在濱河造成了極大的恐慌,老刑警劉巖衷佃,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件趟卸,死亡現(xiàn)場離奇詭異,居然都是意外死亡氏义,警方通過查閱死者的電腦和手機锄列,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來惯悠,“玉大人邻邮,你說我怎么就攤上這事】松簦” “怎么了筒严?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長情萤。 經常有香客問我鸭蛙,道長,這世上最難降的妖魔是什么筋岛? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任规惰,我火速辦了婚禮,結果婚禮上泉蝌,老公的妹妹穿的比我還像新娘歇万。我一直安慰自己,他們只是感情好勋陪,可當我...
    茶點故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布贪磺。 她就那樣靜靜地躺著,像睡著了一般诅愚。 火紅的嫁衣襯著肌膚如雪寒锚。 梳的紋絲不亂的頭發(fā)上劫映,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天,我揣著相機與錄音刹前,去河邊找鬼泳赋。 笑死,一個胖子當著我的面吹牛喇喉,可吹牛的內容都是我干的祖今。 我是一名探鬼主播,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼拣技,長吁一口氣:“原來是場噩夢啊……” “哼千诬!你這毒婦竟也來了?” 一聲冷哼從身側響起膏斤,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤徐绑,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后莫辨,有當地人在樹林里發(fā)現(xiàn)了一具尸體傲茄,經...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年沮榜,在試婚紗的時候發(fā)現(xiàn)自己被綠了盘榨。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡敞映,死狀恐怖较曼,靈堂內的尸體忽然破棺而出磷斧,到底是詐尸還是另有隱情振愿,我是刑警寧澤,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布弛饭,位于F島的核電站冕末,受9級特大地震影響,放射性物質發(fā)生泄漏侣颂。R本人自食惡果不足惜档桃,卻給世界環(huán)境...
    茶點故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望憔晒。 院中可真熱鬧藻肄,春花似錦、人聲如沸拒担。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽从撼。三九已至州弟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背婆翔。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工拯杠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人啃奴。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓潭陪,卻偏偏與公主長得像,于是被迫代替她去往敵國和親纺腊。 傳聞我的和親對象是個殘疾皇子畔咧,可洞房花燭夜當晚...
    茶點故事閱讀 43,724評論 2 351

推薦閱讀更多精彩內容