2015-02-17 93 views
2

我想将消息从Android Wear设备发送到连接的手机。 Android智能手机应用程序是使用本地Java编写的并正在运行。磨损应用程序是用Xamarin编写的,不工作。 这是我走到这一步:Android Wear Xamarin消息

public class MainActivity : Activity, IMessageApiMessageListener, 
    IGoogleApiClientConnectionCallbacks, IResultCallback 
{ 
    private IGoogleApiClient mApiClient; 
    private SensorManager _SensorManager; 

    private Sensor _Gyroscop; 
    private static String WEAR_MESSAGE_PATH = "//message"; 
    protected override void OnCreate (Bundle bundle) 
    { 
     base.OnCreate (bundle); 
     // Set our view from the "main" layout resource 
     SetContentView (Resource.Layout.Main); 

     var v = FindViewById<WatchViewStub> (Resource.Id.watch_view_stub); 
     v.LayoutInflated += delegate { 
     }; 

     if(_SensorManager == null) { 
      _SensorManager = (SensorManager)GetSystemService(SensorService); 
     } 

     SensorListener s = new SensorListener(); 
     _Gyroscop = _SensorManager.GetDefaultSensor (SensorType.Gyroscope); 
     _SensorManager.RegisterListener (s, _Gyroscop,SensorDelay.Normal); 
     s.SensorChangedEvent += delegate(SensorEvent e) { 
      if(mApiClient.IsConnected){ 
       sendMessage(WEAR_MESSAGE_PATH,"Test"); 
      } 
     }; 
     initGoogleApiClient(); 
    } 

    private void initGoogleApiClient() { 
    mApiClient = new GoogleApiClientBuilder(this) 
       .AddApi(WearableClass.Api) 
       .AddConnectionCallbacks(this) 
       .Build(); 

    if (mApiClient != null && !(mApiClient.IsConnected || mApiClient.IsConnecting)) { 
     mApiClient.Connect(); 
     } 
    } 



    private void sendMessage( String path, String text) { 
     WearableClass.NodeApi 
        .GetConnectedNodes (mApiClient) 
        .SetResultCallback (this); 
    } 

    public void OnResult (Java.Lang.Object raw) 
    { 
     Exception nodeException, messageException; 
     try { 
      //send the message 
      var nodeResult = raw.JavaCast<INodeApiGetConnectedNodesResult>(); 
      foreach (var node in nodeResult.Nodes) 
      WearableClass.MessageApi.SendMessage (mApiClient, node.Id, WEAR_MESSAGE_PATH, StringToByteArray("Test")).SetResultCallback (this); //will go to second try/catch block 
      return; 
     } catch (Exception e) { 
      nodeException = e; 
     } 
     try { 
      //check that it worked correctly 
      var messageResult = raw.JavaCast<IMessageApiSendMessageResult>(); 
      if (!messageResult.Status.IsSuccess)      
       Console.WriteLine ("Problem"); 
      return; 
     } catch (Exception e) { 
      messageException = e; 
     } 
    } 

    public void OnConnected (Bundle p0) 
    { 
     WearableClass.MessageApi.AddListener (mApiClient, this); 
    } 

    public void OnConnectionSuspended (int p0) 
    { 
     WearableClass.MessageApi.RemoveListener (mApiClient, this); 
    } 
} 

的问题是,手机计量不接收消息。

+0

您是否设法解决问题?我正在努力从手持设备发送消息(或数据)(或反之)。发送时,*接收*应用程序立即崩溃。我主要使用这两个引用:http://android-wear-docs.readthedocs.org/en/latest/sync.html#first-wearable-message和http://toastdroid.com/2014/08/18/messageapi -simple-conversations-with-android-wear/ – Falko 2015-02-24 09:47:54

+0

我的Android版单机版发送问题未解决。我已经切换到本地Java,并且这个接口可以毫无问题地工作。我使用这个教程:http://www.binpress.com/tutorial/a-guide-to-the-android-wear-message-api/152[link] – user1120866 2015-02-24 12:04:07

回答

6

我终于完成了实施一个最小的工作示例,演示掌上电脑和磨损之间的通信。它是一个纯粹的Xamarin解决方案,可以发送消息以及双向数据地图。

由于发送和接收信息对手持设备和穿戴工作方式相同,我创建了一个名为“通信”的共享项目。它包含一个“Communicator”类,它由两个应用程序使用。

此外,在这个简单的例子中,两个主要活动的AXML和C#实现是相同的。我们将在每个设备上看到两个按钮,允许发送新消息或一些数据。

通信器

Communicator类从Java.Lang.Object派生并实现两个侦听器接口。

public class Communicator: Java.Lang.Object, IMessageApiMessageListener, IDataApiDataListener 
{ 
    ... 

它包含一个IGoogleApiClient

readonly IGoogleApiClient client; 

和存储共同路径:

const string path = "/communicator"; 

(这两个API,消息API和数据API,需要一个 “路径” 作为一种通信通道标识符,对所有消息使用相同的路径是第一次尝试,但在增加更复杂的应用中的流量时可能会产生噪音。)

Communicator使用Android Context构建并构建IGoogleApiClient

public Communicator(Context context) 
    { 
     client = new GoogleApiClientBuilder(context) 
      .AddApi(WearableClass.Api) 
      .Build(); 
    } 

当恢复或暂停活动时,将会调用以下方法。它们连接或断开client和注册或注销Communicator作为消息/数据监听器:

public void Resume() 
    { 
     if (!client.IsConnected) { 
      client.Connect(); 
      WearableClass.MessageApi.AddListener(client, this); 
      WearableClass.DataApi.AddListener(client, this); 
     } 
    } 

    public void Pause() 
    { 
     if (client != null && client.IsConnected) { 
      client.Disconnect(); 
      WearableClass.MessageApi.RemoveListener(client, this); 
      WearableClass.DataApi.RemoveListener(client, this); 
     } 
    } 

有两种,而类似的方法用于将信息发送,一个用于消息和一个用于数据的地图。为了避免阻塞UI,这两项任务都在后台线程上执行。请注意,消息被发送到特定的“节点”(=设备),而数据没有特定的接收器。

public void SendMessage(string message) 
    { 
     Task.Run(() => { 
      foreach (var node in Nodes()) { 
       var bytes = Encoding.Default.GetBytes(message); 
       var result = WearableClass.MessageApi.SendMessage(client, node.Id, path, bytes).Await(); 
       var success = result.JavaCast<IMessageApiSendMessageResult>().Status.IsSuccess ? "Ok." : "Failed!"; 
       Console.WriteLine(string.Format("Communicator: Sending message {0}... {1}", message, success)); 
      } 
     }); 
    } 

    public void SendData(DataMap dataMap) 
    { 
     Task.Run(() => { 
      var request = PutDataMapRequest.Create(path); 
      request.DataMap.PutAll(dataMap); 
      var result = WearableClass.DataApi.PutDataItem(client, request.AsPutDataRequest()).Await(); 
      var success = result.JavaCast<IDataApiDataItemResult>().Status.IsSuccess ? "Ok." : "Failed!"; 
      Console.WriteLine(string.Format("Communicator: Sending data map {0}... {1}", dataMap, success)); 
     }); 
    } 

当然,我们需要接收数据的方法。它们实际上由上述两个接口定义并需要实施。 (OnDataChanged检查正确的路径,因为数据可能奉献给这个应用程序。)

public void OnMessageReceived(IMessageEvent messageEvent) 
    { 
     var message = Encoding.Default.GetString(messageEvent.GetData()); 
     Console.WriteLine(string.Format("Communicator: Message received \"{0}\"", message)); 
     MessageReceived(message); 
    } 

    public void OnDataChanged(DataEventBuffer p0) 
    { 
     Console.WriteLine(string.Format("Communicator: Data changed ({0} data events)", p0.Count)); 
     for (var i = 0; i < p0.Count; i++) { 
      var dataEvent = p0.Get(i).JavaCast<IDataEvent>(); 
      if (dataEvent.Type == DataEvent.TypeChanged && dataEvent.DataItem.Uri.Path == path) 
       DataReceived(DataMapItem.FromDataItem(dataEvent.DataItem).DataMap); 
     } 
    } 

他们每个人都调用以下事件之一。

public event Action<string> MessageReceived = delegate {}; 

    public event Action<DataMap> DataReceived = delegate {}; 

最后但并非最不重要的,我们需要检索所有连接的节点的方法:

IList<INode> Nodes() 
    { 
     var result = WearableClass.NodeApi.GetConnectedNodes(client).Await(); 
     return result.JavaCast<INodeApiGetConnectedNodesResult>().Nodes; 
    } 

布局

为了简单起见,这两个应用程序使用相同的布局。它包含两个按钮,每个按钮的总屏幕尺寸为50%。

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"> 
    <Button 
     android:id="@+id/messageButton" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:layout_weight="1" 
     android:text="Send message" /> 
    <Button 
     android:id="@+id/dataButton" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:layout_weight="1" 
     android:text="Send data" /> 
</LinearLayout> 

主要活动

这两个应用程序实现从Activity衍生的MainActivity

public class MainActivity : Activity 
{ 
    ... 

每个活动都有一个communicator包封所有的通信相关的代码。

Communicator communicator; 

截至OnCreate结束时,我们实例化communicator

 communicator = new Communicator(this); 

和线材均messageButton

 var messageButton = FindViewById<Button>(Resource.Id.messageButton); 
     messageButton.Click += (sender, e) => communicator.SendMessage("time: " + DateTime.Now.ToString("T")); 
     communicator.MessageReceived += message => RunOnUiThread(() => messageButton.Text = message); 

还有dataButton

 var dataButton = FindViewById<Button>(Resource.Id.dataButton); 
     dataButton.Click += delegate { 
      var dataMap = new DataMap(); 
      dataMap.PutString("time", DateTime.Now.ToString("T")); 
      communicator.SendData(dataMap); 
     }; 
     communicator.DataReceived += dataMap => RunOnUiThread(() => dataButton.Text = dataMap.ToString()); 

(我们使用格式标识符“T”生成包括秒的“长时间”字符串。这种方式在大多数情况下字符串将从一次点击变为另一次。这一点很重要,因为发送相同数据映射两次不会触发OnDataChanged事件处理程序)

最后,我们ResumePausecommunicator在正确的地方!

protected override void OnResume() 
    { 
     base.OnResume(); 

     communicator.Resume(); 
    } 

    protected override void OnPause() 
    { 
     communicator.Pause(); 

     base.OnPause(); 
    } 

清单

由于我们使用的是Google移动服务,因此我们需要将以下行写入AndroidManifest.xml文件的<application>标签:

​​

结果

当打开的应用程序,我们看到下面的画面。

几次点击之后,这两个应用发送的当前时间,以彼此,无论是经由消息API或数据API。现在屏幕如下所示。

注意,其中有些数据映射的发送者将收到它。因此,dataButton上的时间在两台设备上都相同。相反,消息只发送给所有其他节点,因此不会返回给发件人。

+0

该项目的任何更新,希望实现类似的东西?谢谢 – jonik 2015-09-30 04:48:03

1

我终于找到我的错误和他们不沟通的原因。问题在于两个应用程序有不同的包名(你可以在AndroidManifest.xml中设置它们)。在将它们设置为相同的名称之后,通信起作用。谢谢Falko对你的大力帮助:)。