Android 發(fā)送與接收消息

2018-08-02 17:54 更新

編寫:wly2014 - 原文: http://developer.android.com/training/wearables/data-layer/messages.html

使用MessageApi發(fā)送消息,要附加以下幾項:

  • 任一payload(可選)
  • 唯一標識消息動作的路徑

不像數(shù)據(jù)元,Messages(消息)在手持和可穿戴應用之間沒有同步。Messages是單向交流機制,這有利于遠程進程調用(RPC),比如:發(fā)送消息到可穿戴設備以開啟activity。

多個可穿戴設備可以連接到一臺用戶的手持設備。在網(wǎng)絡中每個已連接的設備被視為一個節(jié)點node)。由于有多個已連接的設備,我們必須考慮哪個節(jié)點收到消息。例如,在一個在可穿戴設備上接收語音數(shù)據(jù)的語音轉錄應用中,我們應該發(fā)送消息到一個具有處理能力和電池容量的節(jié)點來處理請求,例如一個手持式設備。

Note: Google Play services 7.3.0版之前,一次只有一個可穿戴設備可以連接到手持設備。我們需要將現(xiàn)有的代碼升級,以考慮到多個連接節(jié)點的功能。如果我們不作出修改,那么我們的消息可能不會傳到想要的設備。

發(fā)送消息

一個可穿戴應用可以為用戶提供如語音轉錄等功能。用戶可以對著他們可穿戴設備的麥克風說話,然后就會將語音保存成一個筆記。由于一個可穿戴設備通常沒有足夠的處理能力和電池容量來處理語音轉錄activity,所以應用應該將這個工作留給一個更加有能力的、已連接的設備來處理。

下面幾個小節(jié)介紹如何通知那些可以處理activity請求的設備節(jié)點,發(fā)現(xiàn)有能力滿足請求的節(jié)點,并發(fā)送消息給那些節(jié)點。

通知節(jié)點功能

使用 MessageApi 類發(fā)送請求,來從一個可穿戴設備啟動一個手持設備的activity。由于一個手持式設備可以連接多個可穿戴設備,所以可穿戴應用需要確定一個已連接的節(jié)點是否有能力啟動activity。在我們的手持式應用中,通知其它節(jié)點:我們的手持式應用所在的節(jié)點提供了上述指定的功能。

為了把我們的手持式應用的功能通知其它節(jié)點,需要:

  1. 在工程的 res/values/ 目錄下創(chuàng)建一個名為 wear.xml 的 XML 文件。
  2. 在 wear.xml 文件中添加一個名為 android_wear_capabilities 的資源。
  3. 定義設備可以提供的功能。

Note: 功能是我們自定義的字符串,它在我們的應用中必須是唯一的。

下面這個例子介紹了如何將一個名為 voice_transcription 的功能添加到 wear.xml中:

<resources>
    <string-array name="android_wear_capabilities">
        <item>voice_transcription</item>
    </string-array>
</resources>

檢索具有相關功能的節(jié)點

首先,我們可以通過調用 CapabilityApi.getCapability() 方法來檢測具有相關功能的節(jié)點。下面的例子介紹了如何手動檢索具有 voice_transcription 功能的節(jié)點:

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

為了在連接到可穿戴設備的時候檢測有能力的節(jié)點,注冊一個 CapabilityApi.CapabilityListener() 實例到 GoogleApiClient。下面的例子介紹了如何注冊該監(jiān)聽器和檢索具有 voice_transcription 功能的節(jié)點。

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)建一個繼承 WearableListenerService 的 service 來檢測功能的變化,我們可能要重寫 onConnectedNodes()) 方法來監(jiān)聽細微的連接細節(jié),例如,一個可穿戴設備與手持式設備從Wi-Fi連接切換到藍牙連接。關于一個實現(xiàn)的例子,請查看在 FindMyPhone 示例中的 DisconnectListenerService類。更多關于如何監(jiān)聽重要事件的內容,請見監(jiān)聽數(shù)據(jù)層事件。

檢測到有能力的節(jié)點之后,需要確定將消息發(fā)送到哪里。我們需要選擇與可穿戴設備鄰近的節(jié)點,這樣可以最小化多個節(jié)點間的消息路由。一個鄰近的節(jié)點被定義為一個直接與設備連接的節(jié)點。調用 Node.isNearby()) 來確定一個節(jié)點是否是鄰近的。

下面的例子介紹了如何確定最佳節(jié)點:

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é)點,使用 MessageApi 發(fā)送消息。

下面的例子介紹了如何從一個可穿戴設備發(fā)送消息到具有語音轉錄功能的節(jié)點。在我們試圖發(fā)送消息之前,需要判斷節(jié)點是否可用。這個調用是同步的,它在系統(tǒng)將傳送的消息放到隊列前會一直阻塞。

Note: 一個成功結果碼并不保證消息是否傳送成功。如果我們的應用需要數(shù)據(jù)的可靠性,那么使用 DataItem 對象或者 ChannelApi 類在設備間發(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 了解更多關于異步和同步調用,以及何時使用哪個。

我們還可以廣播消息給所有已連接的節(jié)點。為了獲得我們可以發(fā)送消息的已連接節(jié)點,需要實現(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;
}

接收消息

為了在收到消息時被提醒,我們可以實現(xiàn) MessageListener 接口來提供消息事件的監(jiān)聽。然后,我們需要在 MessageApi.addListener() 方法中注冊監(jiān)聽。這個例子展示如何通過檢查 VOICE_TRANSCRIPTION_MESSAGE_PATH來實現(xiàn)監(jiān)聽器。如果該條件是true,就會啟動特定的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);
    }
}

這僅是實現(xiàn)更多細節(jié)的一小段。關于如何在 service 或 activity 實現(xiàn)完整的監(jiān)聽,請參見 監(jiān)聽數(shù)據(jù)傳輸層事件 。


以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號