標籤:else 結合 接收 ges creat 過濾 hot 系統 時間
程式間可以互相通訊是Android程式中最棒的功能之一。當一個功能已存在於其他app中,且並不是本程式的核心功能時,完全沒有必要重新對其進行編寫。
本章節會講述一些通在不同程式之間通過使用Intent APIs與ActionProvider對象來發送與接受content的常用方法。
Lessons
給其他App發送簡單的資料
在構建一個intent時,必須指定這個intent需要觸發的actions。Android定義了一些actions,比如ACTION_SEND,該action表明該intent用於從一個activity發送資料到另外一個activity的,甚至可以是跨進程之間的資料發送。
為了發送資料到另外一個activity,我們只需要指定資料與資料的類型,系統會自動識別出能夠相容接受的這些資料的activity。如果這些選擇有多個,則把這些activity顯示給使用者進行選擇;如果只有一個,則立即啟動該Activity。同樣的,我們可以在manifest檔案的Activity描述中添加接受的資料類型。
在不同的程式之間使用intent收發資料是在社交分享內容時最常用的方法。Intent使使用者能夠通過最常用的程式進行快速簡單的分享資訊。
注意:為ActionBar添加分享功能的最佳方法是使用ShareActionProvider,其運行與API level 14以上的系統。ShareActionProvider將在第3課中進行詳細介紹。
分享常值內容(Send Text Content)
ACTION_SEND最直接常用的地方是從一個Activity發送常值內容到另外一個Activity。例如,Android內建的瀏覽器可以將當前顯示頁面的URL作為常值內容分享到其他程式。這一功能對於通過郵件或者社交網路來分享文章或者網址給好友而言是非常有用的。下面是一段Sample Code:
Intent sendIntent = new Intent();sendIntent.setAction(Intent.ACTION_SEND);sendIntent.putExtra(Intent.EXTRA_TEXT, "This is my text to send.");sendIntent.setType("text/plain");startActivity(sendIntent);
如果裝置上安裝有某個能夠匹配ACTION_SEND且MIME類型為text/plain的程式,則Android系統會立即執行它。若有多個匹配的程式,則系統會把他們都給篩選出來,並呈現Dialog給使用者進行選擇。
如果為intent調用了Intent.createChooser(),那麼Android總是會顯示可供選擇。這樣有一些好處:
- 即使使用者之前為這個intent設定了預設的action,選擇介面還是會被顯示。
- 如果沒有匹配的程式,Android會顯示系統資訊。
- 我們可以指定選擇介面的標題。
下面是更新後的代碼:
Intent sendIntent = new Intent();sendIntent.setAction(Intent.ACTION_SEND);sendIntent.putExtra(Intent.EXTRA_TEXT, "This is my text to send.");sendIntent.setType("text/plain");startActivity(Intent.createChooser(sendIntent, getResources().getText(R.string.send_to));
如下:
另外,我們可以為intent設定一些標準的附加值,例如:EXTRA_EMAIL, EXTRA_CC, EXTRA_BCC, EXTRA_SUBJECT等。然而,如果接收程式沒有針對那些做特殊的處理,則不會有對應的反應。
注意:一些e-mail程式,例如Gmail,對應接收的是EXTRA_EMAIL與EXTRA_CC,他們都是String類型的,可以使用putExtra(string,string[])方法來添加至intent中。
分享二進位內容(Send Binary Content)
分享二進位的資料需要結合設定特定的MIME類型,需要在
EXTRA_STREAM`裡面放置資料的URI,下面有個分享圖片的例子,該例子也可以修改用於分享任何類型的位元據:
Intent shareIntent = new Intent();shareIntent.setAction(Intent.ACTION_SEND);shareIntent.putExtra(Intent.EXTRA_STREAM, uriToImage);shareIntent.setType("image/jpeg");startActivity(Intent.createChooser(shareIntent, getResources().getText(R.string.send_to)));
請注意以下內容:
- 我們可以使用
*/*
這樣的方式來指定MIME類型,但是這僅僅會match到那些能夠處理一般資料類型的Activity(即一般的Activity無法詳盡所有的MIME類型)
- 接收的程式需要有訪問URI資源的許可權。下面有一些方法來處理這個問題:
- 將資料存放區在ContentProvider中,確保其他程式有訪問provider的許可權。較好的提供存取權限的方法是使用 per-URI permissions,其對接收程式而言是只是暫時擁有該許可許可權。類似於這樣建立ContentProvider的一種簡單的方法是使用FileProvider helper類。
- 使用MediaStore系統。MediaStore系統主要用於音視頻及圖片的MIME類型。但在Android3.0之後,其也可以用於儲存非多媒體類型。
發送多塊內容(Send Multiple Pieces of Content)
為了同時分享多種不同類型的內容,需要使用ACTION_SEND_MULTIPLE
與指定到那些資料的URIs列表。MIME類型會根據分享的混合內容而不同。例如,如果分享3張JPEG的圖片,那麼MIME類型仍然是image/jpeg
。如果是不同圖片格式的話,應該是用image/*
來匹配那些可以接收任何圖片類型的activity。如果需要分享多種不同類型的資料,可以使用*/*
來表示MIME。像前面描述的那樣,這取決於那些接收的程式解析並處理我們的資料。下面是一個例子:
ArrayList<Uri> imageUris = new ArrayList<Uri>();imageUris.add(imageUri1); // Add your image URIs hereimageUris.add(imageUri2);Intent shareIntent = new Intent();shareIntent.setAction(Intent.ACTION_SEND_MULTIPLE);shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, imageUris);shareIntent.setType("image/*");startActivity(Intent.createChooser(shareIntent, "Share images to.."));
當然,請確保指定到資料的URIs能夠被接收程式所訪問(添加存取權限)。
接收從其他App傳送來的資料
就像我們的程式能夠分享資料給其他程式一樣,其也能方便的接收來自其他程式的資料。需要考慮的是使用者與我們的程式如何進行互動,以及我們想要從其他程式接收資料的類型。例如,一個社交網路程式可能會希望能夠從其他程式接受文本資料,比如一個有趣的網址連結。Google+的Android用戶端會接受文本資料與單張或者多張圖片。使用者可以簡單的從Gallery程式選擇一張圖片來啟動Google+,並利用其發布文本或圖片。
更新我們的manifest檔案(Update Your Manifest)
Intent filters告訴Android系統一個程式願意接受的資料類型。類似於上一課,我們可以建立intent filters來表明程式能夠接收的action類型。下面是個例子,對三個activit分別指定接受單張圖片,文本與多張圖片。(Intent filter相關資料,請參考Intents and Intent Filters)
<activity android:name=".ui.MyActivity" > <intent-filter> <action android:name="android.intent.action.SEND" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="image/*" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.SEND" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="text/plain" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.SEND_MULTIPLE" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="image/*" /> </intent-filter></activity>
當某個程式嘗試通過建立一個intent並將其傳遞給startActivity來分享一些東西時,我們的程式會被呈現在一個列表中讓使用者進行選擇。如果使用者選擇了我們的程式,相應的activity會被調用開啟,這個時候就是我們如何處理擷取到的資料的問題了。
處理接受到的資料(Handle the Incoming Content)
為了處理從Intent帶來的資料,可以通過調用getIntent()方法來擷取到Intent對象。拿到這個對象後,我們可以對其中面的資料進行判斷,從而決定下一步行為。請記住,如果一個activity可以被其他的程式啟動,我們需要在檢查intent的時候考慮這種情況(是被其他程式而調用啟動的)。
void onCreate (Bundle savedInstanceState) { ... // Get intent, action and MIME type Intent intent = getIntent(); String action = intent.getAction(); String type = intent.getType(); if (Intent.ACTION_SEND.equals(action) && type != null) { if ("text/plain".equals(type)) { handleSendText(intent); // Handle text being sent } else if (type.startsWith("image/")) { handleSendImage(intent); // Handle single image being sent } } else if (Intent.ACTION_SEND_MULTIPLE.equals(action) && type != null) { if (type.startsWith("image/")) { handleSendMultipleImages(intent); // Handle multiple images being sent } } else { // Handle other intents, such as being started from the home screen } ...}void handleSendText(Intent intent) { String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT); if (sharedText != null) { // Update UI to reflect text being shared }}void handleSendImage(Intent intent) { Uri imageUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM); if (imageUri != null) { // Update UI to reflect image being shared }}void handleSendMultipleImages(Intent intent) { ArrayList<Uri> imageUris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); if (imageUris != null) { // Update UI to reflect multiple images being shared }}
請注意,由於無法知道其他程式發送過來的資料內容是文本還是其他類型的資料,若資料量巨大,則需要大量處理時間,因此我們應避免在UI線程裡面去處理那些擷取到的資料。
更新UI可以像更新EditText一樣簡單,也可以是更加複雜一點的操作,例如過濾出感興趣的圖片。這完全取決於我們的應用接下來要做些什麼。
添加一個簡便的分享功能
Android4.0之後系統中ActionProvider的引入使在ActionBar中添加分享功能變得更為簡單。它會handle出現share功能的appearance與behavior。在ShareActionProvider的例子裡面,我們只需要提供一個share intent,剩下的就交給ShareActionProvider來做。
更新菜單聲明(Update Menu Declarations)
使用ShareActionProvider的第一步,在menu resources對應item中定義android:actionProviderClass
屬性。
<menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/menu_item_share" android:showAsAction="ifRoom" android:title="Share" android:actionProviderClass="android.widget.ShareActionProvider" /> ...</menu>
這表明了該item的appearance與function需要與ShareActionProvider匹配。此外,你還需要告訴provider想分享的內容。
Set the Share Intent(設定分享的intent)
為了實現ShareActionProvider的功能,我們必須為它提供一個intent。該share intent應該像第一課講的那樣,帶有ACTION_SEND
和附加資料(例如EXTRA_TEXT
與 EXTRA_STREAM
)的。使用ShareActionProvider的例子如下:
private ShareActionProvider mShareActionProvider;...@Overridepublic boolean onCreateOptionsMenu(Menu menu) { // Inflate menu resource file. getMenuInflater().inflate(R.menu.share_menu, menu); // Locate MenuItem with ShareActionProvider MenuItem item = menu.findItem(R.id.menu_item_share); // Fetch and store ShareActionProvider mShareActionProvider = (ShareActionProvider) item.getActionProvider(); // Return true to display menu return true;}// Call to update the share intentprivate void setShareIntent(Intent shareIntent) { if (mShareActionProvider != null) { mShareActionProvider.setShareIntent(shareIntent); }}
也許在建立菜單的時候僅僅需要設定一次share intent就滿足需求了,或者說我們可能想先設定share intent,然後根據UI的變化來對intent進行更新。例如,當在Gallery裡面全圖查看照片的時候,share intent會在切換圖片時候進行改變。 更多關於ShareActionProvider的內容,請查看Action Bar 。
12) 十分鐘學會android--APP通訊傳遞訊息之簡單資料轉送