讓你的Android應用與外部元素互動起來

傳送門 ☞ 輪子的專欄 ☞ 轉載請註明 ☞ http://blog.csdn.net/leverage_1229
html

        一個Android應用程序一般有幾個activities。每一個act顯示一個用戶接口容許用戶執行一個指定的任務。用戶從一個act到另外一個act,你的App必須使用一個Intent對象來定義你App想作些什麼事。當你經過一個Intent調用startActivity()方法時,系統會使用Intent來鑑定和啓動合適的App組件。一個Intent能夠明確的啓動一個特定的組件(如一個特定的act實例)或隱式啓動任何能夠處理預約動做的組件,本章咱們將講述怎麼使用Intent來執行與其餘Apps的一些交互,例如啓動另外一個App,從那個App接收結果。並使你的應用程序可以響應來自其餘App的intents。java

1發送用戶到另外一個App

        Android最重要的一個特性之一就是發送用戶到另外一個App並基於「動做」來執行它的能力。例如,若是你的app有商業地址想要顯示在地圖上,你不得不在你的App中新建一個activity來顯示地圖。其實更好的辦法是使用Intent發送一個查看地圖的外部請求。Android系統會啓動那個能查看地址的App。一般,咱們使用一個明確的Intent,它定義的明確的類名。然而,當你想有一個單獨的應用程序執行時,如「查看地圖」,你必須使用一個隱式的Intent。本節講述如何爲一個特定的動做建立隱含的意圖,以及怎樣用它來啓動執行另外一個應用程序中的Activity。

1.1構建一個隱式的Intent

        隱式intents不用申明啓動組件的類名,但須要申明執行的動做。動做指定你想要作的事情,如view(查看),edit(編輯),send(發送)或得到某事物。Intents常常包託一些與動做相關聯的稅局,如你想要查看的地址,或者你想要發送的email信息。這取決於你想要建立的Intent所發送的數據,數據多是一個Uri或intent根本不須要數據也能發送。
使用Uri數據撥打電話:
Uri number = Uri.parse("tel:5551234");
Intent callIntent = new Intent(Intent.ACTION_DIAL, number);
        當你的app經過startActivity()調用intent時,電話app根據給定的電話號碼發起呼叫。
查看一個地圖:
// 基於地址的地圖點
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
// 或基於經緯度的地圖點
// Uri location = Uri.parse("geo:37.422219,-122.08364?z=14"); // z參數表示縮放級別
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);
查看一個web頁面:
Uri webpage = Uri.parse("http://www.android.com");
Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);
        其餘種類的隱式intents須要」extra」數據來提供不一樣的數據類型,如一個字符串。你能使用putExtra()方法來添加一個或更多extra 數據。默認的,系統經過基於Uri的intent來肯定適當的MIME(Multipurpose Internet Mail Extensions)類型。若是你在intent中不包含一個Uri,你應該使用setType()來指定intent相關聯的數據類型。設置MIME類型來進一步指定activities將要接收的intent類型。
發送帶有附件的電子郵件:
Intent emailIntent = new Intent(Intent.ACTION_SEND);
//沒有Uri的intent,因此須要聲明」text/plain」的MIME類型
emailIntent.setType(HTTP.PLAIN_TEXT_TYPE);
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] {"jon@example.com"}); // 收件人
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"));
建立一個日曆事件:
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");
注意: 對於日曆事件的intent只在API Level或更高版本下才支持。

1.2驗證一個App接收的Intent

        咱們老是應該在調用一個intent以前先包含一個驗證。這是一個好的習慣,由於若是你在app中調用intent後,若是沒有可用的設備,那麼你的app會崩潰.爲了驗證那個activity可用,咱們能夠調用queryIntentActivities()來得到一個list,若是返回的List不爲空,那麼你能安全的使用intent。
PackageManager packageManager = getPackageManager();
List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
boolean isIntentSafe = activities.size() > 0;
        如isIntentSafe爲true,那麼表示至少有一個app能響應咱們的intent。若是false,表示沒有一個app能處理這個intent。

1.3使用Intent啓動一個Activity

        你能夠建立intent並設置extra的信息,而後調用startActivity()。若是系統識別有多個activity能處理這個intent,那麼它會顯示一個對話框讓你自主選擇。若是隻有一個activity的話,系統會當即啓動這個activity。
        讓咱們看看以下的代碼,看它是怎麼啓動activity的:
// 構建intent
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);
// 驗證上面的mapIntent
PackageManager packageManager = getPackageManager();
List<ResolveInfo> activities = packageManager.queryIntentActivities(mapIntent, 0);
boolean isIntentSafe = activities.size() > 0;
// 若是它是安全的就啓動這個activity
if (isIntentSafe) {
    startActivity(mapIntent);
}

1.4顯示APP選擇器

        注意當你經過intent使用startActivity()啓動activity時,若是有多個app響應,若是多個應用能夠處理咱們的操做,而且用戶可能想要每次啓動不一樣的app,好比一個」分享」的動做,分享的渠道可能有多個app組成,這樣用戶每次可能使用不一樣的app。那麼咱們可使用createChooser()來建立顯示選擇器。
Intent intent = new Intent(Intent.ACTION_SEND);
...
// 用於標題的文本資源例如"Share this photo with"
String title = getResources().getText(R.string.chooser_title);
// 建立並啓動chooser
Intent chooser = Intent.createChooser(intent, title);
startActivity(chooser);

2從Activity得到結果

        啓動另外一個activity並不必定是單向的。咱們還能夠啓動另外一個activity,並接收返回結果.。若是須要接收返回結果,咱們可使用startActivityForResult()。L例如。你的應用啓動一個攝像機app並接收拍攝照片的結果。固然,得到響應的activity必須被設計爲返回一個結果,當它這麼作時,它發送一個intent對象的結果。你的activity在onActivityResult()回調方法中會接收到這個intent。雖然咱們可使用明確的和隱式的intent,但這裏實際建議你應該使用一個明確的intent,以確保收到了預期的結果。

2.1啓動Activity

        使用startActivityForResult()方法,須要傳遞一個額外的int參數。Int參數的意思爲」request code」,就是標識一個請求。當收到intent結果時,回調提供了相同的請求的代碼,使應用程序能夠正確識別結果,並決定如何處理它。
如何啓動一個activity並容許用戶選擇一個聯繫人:
static final int PICK_CONTACT_REQUEST = 1;  // request code
...
private void pickContact() {
    Intent pickContactIntent = new Intent(Intent.ACTION_PICK, new Uri("content://contacts"));
    pickContactIntent.setType(Phone.CONTENT_TYPE); 
    startActivityForResult(pickContactIntent, PICK_CONTACT_REQUEST);
}

2.2接收一個結果

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // 檢查響應的請求
    if (requestCode == PICK_CONTACT_REQUEST) {
        // 確保請求是成功的
        if (resultCode == RESULT_OK) {
            // Do something...
        }
    }
}
        爲了成功地處理結果,你必須明白,intent結果的格式將是什麼。例如,People app(早些版本叫Contacts app)始終用content URI返回結果並識別被選擇的聯繫人,Camera app在返回一個Bitmap。
將上面的代碼擴展一下,讓咱們看下怎樣讀取聯繫人數據:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    //檢查響應的請求
    if (requestCode == PICK_CONTACT_REQUEST) {
        //確保請求是成功的
        if (resultCode == RESULT_OK) {
            // 得到指向選定聯繫人的URI
            Uri contactUri = data.getData();
            //咱們只須要號碼(NUMBER)列 
            String[] projection = {Phone.NUMBER};
 
            // 在聯繫人中執行查詢,得到NUMBER column
            // 咱們不須要挑選或排序
            // 提示:  query()方法應該在單獨的線程執行,避免阻塞UI線程
            // 考慮使用CursorLoader 執行查詢
            Cursor cursor = getContentResolver()
                    .query(contactUri, projection, null, null, null);
            cursor.moveToFirst();
 
            // 從NUMBER column中檢索電話號碼
            int column = cursor.getColumnIndex(Phone.NUMBER);
            String number = cursor.getString(column);
 
            // 使用電話號碼作些事情
        }
    }
}
注意:Android 2.3 (API level 9)之前,在Contacts Provider執行一個查詢須要申明READ_CONTACTS權限,雖然在2.3開始有一個臨時的權限可讓你去讀取Contacts Provider,但依舊不能查詢。因此無論什麼版本咱們都申明READ_CONTACTS權限便可。

3容許其餘Apps啓動你的Activity

        在android平臺上,若是你要集成facebook的社交功能,那麼你可使用facebokk提供的一個apk,裏面集成了facebook的衆多功能,如分享信息照片等。在實際開發過程當中,可能咱們須要開發這樣的一個相似的apk,別擔憂,android提供這樣的功能而且很容易實現。

3.1添加一個Intent Filter

        咱們須要正確的定義intents,讓activity能更好的處理。每個intent filter應該添加具體的action類型和數據類型。系統可能會發送一個給定的intent到一個activity,若是activity有一個intent filter並符合下列條件的intent對象:
Action
        一個用來執行動做的字符串名字。例如ACTION_SEND或ACTION_VIEW。在intent filter中的<action>節點指定它。必須是全稱,不能使用API常量。
Data
        相關的intent中數據的描述。在intent filter中的<data>節點指定它。在這個節點中使用一個或多個屬性,你能指定MIME類型,一個URI前綴,一個URI組合,或者是以上內容的組合。若是你不須要申明指定的Uri數據,那你僅指定 android:mimeType屬性便可,例如text/plain或image/jpeg。
Category
        提供一種額外的方法來表示activity處理的intent,一般與用戶手勢和開始位置相關。系統支持幾種不一樣的類別,但大部分都不多使用,通常在intent filter中的<category>節點使用CATEGORY_DEFAULT。
下面的<intent-filter>中定義的內容表示在處理ACTION_SEND的intent中使用的數據類型爲文本或圖像。
<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只有一個動做和一種數據類型,但聲明多個<data>,<action>,<category>也是OK的,若是動做和數據類型相互排斥的話,你就應該分開它們。加入你的activity處理文本和圖像,而且使用ACTION_SEND和ACTION_SENDTO intents。這樣就是錯誤的,在這種狀況下你應該使用兩個<intent-filter>來分開它們。由於SENDTO必須使用Uri數據,而且須要sms和smsto的scheme。
<activity android:name="ShareActivity">
    <!—爲發送文本過濾; 接收SENDTO action 使用 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>
    <!—爲發送文本或圖像過濾; 接收SEND action和文本或者圖像數據 -->
    <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>
        爲了接收隱式的intents,咱們必須在<intent-filter>中定義CATEGORY_DEFAULT中,若是沒聲明,那麼你的activity不能解決處理隱式的intents。

3.2 在Activity中處理intent

        爲了決定在你activity中想要處理的動做,你能在啓動activity時讀取intent。在啓動activity時,調用getIntent()方法來檢索啓動activity的intent。你能在任意時刻這麼作,但最好在onCreate()或onStart()中這樣作。
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    //得到啓動activity的intent
    Intent intent = getIntent();
    Uri data = intent.getData();
 
    // 解決intent類型想作什麼
    if (intent.getType().indexOf("image/") != -1) {
        //處理圖像數據
    } else if (intent.getType().equals("text/plain")) {
        // 處理文本
    }
}

3.3 返回一個結果

        若是你想要返回一個結果到你調用的activity,最簡單的就是調用setResult()方法來指定結果代碼和intent結果。當你的操做完成時,用戶若是想要返回到最開始的activity,調用finish()來關閉和destroy你的activity便可。
// 建立intent來傳遞某種結果數據
Intent result = new Intent("com.example.RESULT_ACTION", Uri.parse("content://result_uri");
setResult(Activity.RESULT_OK, result);
finish();
        咱們能夠只指定result code。一般是RESULT_OK或RESULT_CANCELED。你能夠添加額外的intent或者不添加。默認的result code是RESULT_CANCELED。因此若是用戶在你設置result以前執行Back鍵,那麼最初的activity收到的就是RESULT_CANCELED,這並非咱們預計的結果,這個細節請注意。
相關文章
相關標籤/搜索