編寫:wly2014 - 原文: http://developer.android.com/training/wearables/data-layer/messages.html
使用MessageApi發(fā)送消息,要附加以下幾項(xiàng):
不像數(shù)據(jù)元,Messages(消息)在手持和可穿戴應(yīng)用之間沒有同步。Messages是單向交流機(jī)制,這有利于遠(yuǎn)程進(jìn)程調(diào)用(RPC),比如:發(fā)送消息到可穿戴設(shè)備以開啟activity。
多個(gè)可穿戴設(shè)備可以連接到一臺(tái)用戶的手持設(shè)備。在網(wǎng)絡(luò)中每個(gè)已連接的設(shè)備被視為一個(gè)節(jié)點(diǎn)(node)。由于有多個(gè)已連接的設(shè)備,我們必須考慮哪個(gè)節(jié)點(diǎn)收到消息。例如,在一個(gè)在可穿戴設(shè)備上接收語音數(shù)據(jù)的語音轉(zhuǎn)錄應(yīng)用中,我們應(yīng)該發(fā)送消息到一個(gè)具有處理能力和電池容量的節(jié)點(diǎn)來處理請(qǐng)求,例如一個(gè)手持式設(shè)備。
Note: Google Play services 7.3.0版之前,一次只有一個(gè)可穿戴設(shè)備可以連接到手持設(shè)備。我們需要將現(xiàn)有的代碼升級(jí),以考慮到多個(gè)連接節(jié)點(diǎn)的功能。如果我們不作出修改,那么我們的消息可能不會(huì)傳到想要的設(shè)備。
一個(gè)可穿戴應(yīng)用可以為用戶提供如語音轉(zhuǎn)錄等功能。用戶可以對(duì)著他們可穿戴設(shè)備的麥克風(fēng)說話,然后就會(huì)將語音保存成一個(gè)筆記。由于一個(gè)可穿戴設(shè)備通常沒有足夠的處理能力和電池容量來處理語音轉(zhuǎn)錄activity,所以應(yīng)用應(yīng)該將這個(gè)工作留給一個(gè)更加有能力的、已連接的設(shè)備來處理。
下面幾個(gè)小節(jié)介紹如何通知那些可以處理activity請(qǐng)求的設(shè)備節(jié)點(diǎn),發(fā)現(xiàn)有能力滿足請(qǐng)求的節(jié)點(diǎn),并發(fā)送消息給那些節(jié)點(diǎn)。
使用 MessageApi 類發(fā)送請(qǐng)求,來從一個(gè)可穿戴設(shè)備啟動(dòng)一個(gè)手持設(shè)備的activity。由于一個(gè)手持式設(shè)備可以連接多個(gè)可穿戴設(shè)備,所以可穿戴應(yīng)用需要確定一個(gè)已連接的節(jié)點(diǎn)是否有能力啟動(dòng)activity。在我們的手持式應(yīng)用中,通知其它節(jié)點(diǎn):我們的手持式應(yīng)用所在的節(jié)點(diǎn)提供了上述指定的功能。
為了把我們的手持式應(yīng)用的功能通知其它節(jié)點(diǎn),需要:
res/values/
目錄下創(chuàng)建一個(gè)名為 wear.xml
的 XML 文件。wear.xml
文件中添加一個(gè)名為 android_wear_capabilities
的資源。Note: 功能是我們自定義的字符串,它在我們的應(yīng)用中必須是唯一的。
下面這個(gè)例子介紹了如何將一個(gè)名為 voice_transcription
的功能添加到 wear.xml
中:
<resources>
<string-array name="android_wear_capabilities">
<item>voice_transcription</item>
</string-array>
</resources>
首先,我們可以通過調(diào)用 CapabilityApi.getCapability() 方法來檢測(cè)具有相關(guān)功能的節(jié)點(diǎn)。下面的例子介紹了如何手動(dòng)檢索具有 voice_transcription
功能的節(jié)點(diǎn):
private static final String
VOICE_TRANSCRIPTION_CAPABILITY_NAME = "voice_transcription";
private GoogleApiClient mGoogleApiClient;
...
private void setupVoiceTranscription() {
CapabilityApi.GetCapabilityResult result =
Wearable.CapabilityApi.getCapability(
mGoogleApiClient, VOICE_TRANSCRIPTION_CAPABILITY_NAME,
CapabilityApi.FILTER_REACHABLE).await();
updateTranscriptionCapability(result.getCapability());
}
為了在連接到可穿戴設(shè)備的時(shí)候檢測(cè)有能力的節(jié)點(diǎn),注冊(cè)一個(gè) CapabilityApi.CapabilityListener() 實(shí)例到 GoogleApiClient。下面的例子介紹了如何注冊(cè)該監(jiān)聽器和檢索具有 voice_transcription
功能的節(jié)點(diǎn)。
private void setupVoiceTranscription() {
...
CapabilityApi.CapabilityListener capabilityListener =
new CapabilityApi.CapabilityListener() {
@Override
public void onCapabilityChanged(CapabilityInfo capabilityInfo) {
updateTranscriptionCapability(capabilityInfo);
}
};
Wearable.CapabilityApi.addCapabilityListener(
mGoogleApiClient,
capabilityListener,
VOICE_TRANSCRIPTION_CAPABILITY_NAME);
}
Note: 如果我們創(chuàng)建一個(gè)繼承 WearableListenerService 的 service 來檢測(cè)功能的變化,我們可能要重寫 onConnectedNodes() 方法來監(jiān)聽細(xì)微的連接細(xì)節(jié),例如,一個(gè)可穿戴設(shè)備與手持式設(shè)備從Wi-Fi連接切換到藍(lán)牙連接。關(guān)于一個(gè)實(shí)現(xiàn)的例子,請(qǐng)查看在 FindMyPhone 示例中的
DisconnectListenerService
類。更多關(guān)于如何監(jiān)聽重要事件的內(nèi)容,請(qǐng)見監(jiān)聽數(shù)據(jù)層事件。
檢測(cè)到有能力的節(jié)點(diǎn)之后,需要確定將消息發(fā)送到哪里。我們需要選擇與可穿戴設(shè)備鄰近的節(jié)點(diǎn),這樣可以最小化多個(gè)節(jié)點(diǎn)間的消息路由。一個(gè)鄰近的節(jié)點(diǎn)被定義為一個(gè)直接與設(shè)備連接的節(jié)點(diǎn)。調(diào)用 [Node.isNearby()](http://developer.android.com/reference/com/google/android/gms/wearable/Node.html#isNearby()) 來確定一個(gè)節(jié)點(diǎn)是否是鄰近的。
下面的例子介紹了如何確定最佳節(jié)點(diǎn):
private String transcriptionNodeId = null;
private void updateTranscriptionCapability(CapabilityInfo capabilityInfo) {
Set<Node> connectedNodes = capabilityInfo.getNodes();
transcriptionNodeId = pickBestNodeId(connectedNodes);
}
private String pickBestNodeId(Set<Node> nodes) {
String bestNodeId = null;
// Find a nearby node or pick one arbitrarily
for (Node node : nodes) {
if (node.isNearby()) {
return node.getId();
}
bestNodeId = node.getId();
}
return bestNodeId;
}
一旦我們確定了最佳節(jié)點(diǎn),使用 MessageApi 發(fā)送消息。
下面的例子介紹了如何從一個(gè)可穿戴設(shè)備發(fā)送消息到具有語音轉(zhuǎn)錄功能的節(jié)點(diǎn)。在我們?cè)噲D發(fā)送消息之前,需要判斷節(jié)點(diǎn)是否可用。這個(gè)調(diào)用是同步的,它在系統(tǒng)將傳送的消息放到隊(duì)列前會(huì)一直阻塞。
Note: 一個(gè)成功結(jié)果碼并不保證消息是否傳送成功。如果我們的應(yīng)用需要數(shù)據(jù)的可靠性,那么使用 DataItem 對(duì)象或者 ChannelApi 類在設(shè)備間發(fā)送數(shù)據(jù)。
public static final String VOICE_TRANSCRIPTION_MESSAGE_PATH = "/voice_transcription";
private void requestTranscription(byte[] voiceData) {
if (transcriptionNodeId != null) {
Wearable.MessageApi.sendMessage(googleApiClient, transcriptionNodeId,
VOICE_TRANSCRIPTION_MESSAGE_PATH, voiceData).setResultCallback(
new ResultCallback() {
@Override
public void onResult(SendMessageResult sendMessageResult) {
if (!sendMessageResult.getStatus().isSuccess()) {
// Failed to send message
}
}
}
);
} else {
// Unable to retrieve node with transcription capability
}
}
Note: 閱讀 Communicate with Google Play Services 了解更多關(guān)于異步和同步調(diào)用,以及何時(shí)使用哪個(gè)。
我們還可以廣播消息給所有已連接的節(jié)點(diǎn)。為了獲得我們可以發(fā)送消息的已連接節(jié)點(diǎn),需要實(shí)現(xiàn)下面的代碼:
private Collection<String> getNodes() {
HashSet <String>results = new HashSet<String>();
NodeApi.GetConnectedNodesResult nodes =
Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).await();
for (Node node : nodes.getNodes()) {
results.add(node.getId());
}
return results;
}
為了在收到消息時(shí)被提醒,我們可以實(shí)現(xiàn) MessageListener 接口來提供消息事件的監(jiān)聽。然后,我們需要在 MessageApi.addListener() 方法中注冊(cè)監(jiān)聽。這個(gè)例子展示如何通過檢查 VOICE_TRANSCRIPTION_MESSAGE_PATH
來實(shí)現(xiàn)監(jiān)聽器。如果該條件是true,就會(huì)啟動(dòng)特定的activity來處理語音數(shù)據(jù)。
@Override
public void onMessageReceived(MessageEvent messageEvent) {
if (messageEvent.getPath().equals(VOICE_TRANSCRIPTION_MESSAGE_PATH)) {
Intent startIntent = new Intent(this, MainActivity.class);
startIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startIntent.putExtra("VOICE_DATA", messageEvent.getData());
startActivity(startIntent);
}
}
這僅是實(shí)現(xiàn)更多細(xì)節(jié)的一小段。關(guān)于如何在 service 或 activity 實(shí)現(xiàn)完整的監(jiān)聽,請(qǐng)參見 監(jiān)聽數(shù)據(jù)傳輸層事件 。