2016-11-18 24 views
0

我正在尝试使用以下代码从可穿戴设备发送字符串到移动设备。 这个实现是基于https://github.com/twotoasters/Wear-MessageApiDemo/从手表发送字符串到手机

案例有一个在连接到我增加 CONNECTION_TIME_OUT_MS从100到2000(毫秒)设备的时间延迟的问题。

要移动清单我补充一下:的

<service 
    android:name=".ListenerService" > 
    <intent-filter> 
     <action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED" /> 
    </intent-filter> 
</service> 

代替

<service 
    android:name=".ListenerService" > 
    <intent-filter> 
     <action android:name="com.google.android.gms.wearable.BIND_LISTENER" /> 
    </intent-filter> 
</service> 

com.google.android.gms.wearable.BIND_LISTENER已被弃用

的代码编译,但消息没有通过电话接受。

的方法,当接收到消息时

private void showToast(String message) { 

     Log.d(TAG, "received message : " + message); 

    } 

如若listenerService内触发。

该问题是从未收到的消息。我是否正确实现了消息API?

API版本:23

来源:

Mobile组件

开球listenerService:

-------------- --------------------- MainActivity.onCreate ---------------

@Override 
    protected void onCreate(Bundle savedInstanceState) { 

     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     new ListenerService(); 

} 

定义侦听器服务以侦听消息

----------------------------------- ListenerService ------------------

import android.util.Log; 
import android.widget.TextView; 

import com.google.android.gms.wearable.MessageEvent; 
import com.google.android.gms.wearable.WearableListenerService; 

public class ListenerService extends WearableListenerService { 

    private static final String TAG = "ListenerService"; 

    TextView mTextView; 

    @Override 
    public void onMessageReceived(MessageEvent messageEvent) { 
     MainActivity.mTextView.setText("got message"); 
     showToast(messageEvent.getPath()); 
    } 

    private void showToast(String message) { 

     Log.d(TAG, "received message : " + message); 

    } 
} 

定义服务清单中的

-------------- --------------------- AndroidManifest.xml ----------------

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
    package="com.runner"> 

    <uses-permission android:name="android.permission.WAKE_LOCK" /> 
    <uses-permission android:name="android.permission.BODY_SENSORS"/> 
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> 
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> 
    <uses-permission android:name="android.permission.GPS_PROVIDER" /> 
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> 
    <uses-permission android:name="android.permission.INTERNET" /> 

    <application 
     android:allowBackup="true" 
     android:icon="@mipmap/ic_launcher" 
     android:label="@string/app_name" 
     android:supportsRtl="true" 
     android:theme="@style/AppTheme"> 

     <activity android:name=".MainActivity"> 
      <intent-filter> 
       <action android:name="android.intent.action.MAIN" /> 

       <category android:name="android.intent.category.LAUNCHER" /> 
      </intent-filter> 
     </activity> 

     <service 
      android:name=".ListenerService" > 
      <intent-filter> 
       <action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED" /> 
      </intent-filter> 
     </service> 

    </application> 

</manifest> 

磨损部件

MainActivity:

package common; 

import android.content.Context; 
import android.location.Location; 
import android.location.LocationManager; 
import android.os.Bundle; 
import android.support.wearable.activity.WearableActivity; 
import android.support.wearable.view.BoxInsetLayout; 
import android.util.Log; 
import android.view.View; 
import android.widget.TextView; 

import com.google.android.gms.common.api.GoogleApiClient; 
import com.google.android.gms.wearable.Node; 
import com.google.android.gms.wearable.NodeApi; 
import com.google.android.gms.wearable.Wearable; 

import java.text.SimpleDateFormat; 
import java.util.Date; 
import java.util.List; 
import java.util.Locale; 
import java.util.concurrent.TimeUnit; 

public class MainActivity extends WearableActivity { 

    private static final long CONNECTION_TIME_OUT_MS = 2000; 
    private static final String MESSAGE = "Hello Wear!"; 

    private GoogleApiClient client; 
    private String nodeId; 

    private static final String TAG = "MainActivity"; 

    private BoxInsetLayout mContainerView; 


    /** 
    * Initializes the GoogleApiClient and gets the Node ID of the connected device. 
    */ 
    private void initApi() { 
     client = getGoogleApiClient(this); 
     retrieveDeviceNode(); 
    } 

    /** 
    * Returns a GoogleApiClient that can access the Wear API. 
    * @param context 
    * @return A GoogleApiClient that can make calls to the Wear API 
    */ 
    private GoogleApiClient getGoogleApiClient(Context context) { 
     return new GoogleApiClient.Builder(context) 
       .addApi(Wearable.API) 
       .build(); 
    } 

    /** 
    * Connects to the GoogleApiClient and retrieves the connected device's Node ID. If there are 
    * multiple connected devices, the first Node ID is returned. 
    */ 
    private void retrieveDeviceNode() { 
     new Thread(new Runnable() { 
      @Override 
      public void run() { 
       client.blockingConnect(CONNECTION_TIME_OUT_MS, TimeUnit.MILLISECONDS); 
       NodeApi.GetConnectedNodesResult result = 
         Wearable.NodeApi.getConnectedNodes(client).await(); 
       List<Node> nodes = result.getNodes(); 
       if (nodes.size() > 0) { 
        Log.d(TAG, "nodeId "+nodeId); 
        nodeId = nodes.get(0).getId(); 
       } 
       client.disconnect(); 
      } 
     }).start(); 
    } 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     initApi(); 
     sendToast(); 

    } 


    /** 
    * Sends a message to the connected mobile device, telling it to show a Toast. 
    */ 
    private void sendToast() { 
     if (nodeId != null) { 
      new Thread(new Runnable() { 
       @Override 
       public void run() { 
        client.blockingConnect(CONNECTION_TIME_OUT_MS, TimeUnit.MILLISECONDS); 
        Wearable.MessageApi.sendMessage(client, nodeId, MESSAGE, null); 
        client.disconnect(); 
       } 
      }).start(); 
     } 
    } 

} 

更新:

下面是添加到移动模块来监听接收的消息的类:消息监听的

package com.receivers; 

import android.content.BroadcastReceiver; 
import android.content.Context; 
import android.content.Intent; 
import android.util.Log; 

public class MessageListener extends BroadcastReceiver { 

    private static final String TAG = "MessageListener"; 

    @Override 
    public void onReceive(Context context, Intent intent) { 
     String str = intent.getAction(); 
     Log.i(TAG, "onReceive triggered : "+str); 
    } 
} 

配置在AndroidManifest。XML:

<receiver android:name="com.receivers.MessageListener"> 
     <intent-filter> 
      <action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED" /> 
     </intent-filter> 
    </receiver> 

我试过在行String str = intent.getAction();onReceive方法设置一个断点似乎没有被调用。

在wear模块中,方法onNodeFound()似乎在调用此行Wearable.MessageApi.sendMessage(googleApiClient, nodeId, MESSAGE_PATH, "Hello Wear!".getBytes(Charset.forName("UTF-8")));时正确发送消息。我是否正确设置了MessageListener

更新2:

ReceiverActivity:

import android.app.Activity; 
import android.content.BroadcastReceiver; 
import android.content.Context; 
import android.content.Intent; 
import android.content.IntentFilter; 
import android.os.Bundle; 
import android.support.v4.content.LocalBroadcastManager; 
import android.util.Log; 

public class ReceiverActivity extends Activity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver, 
       new IntentFilter("custom-event-name")); 

    } 

    private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() { 
     @Override 
     public void onReceive(Context context, Intent intent) { 
      // Get extra data included in the Intent 
      String message = intent.getStringExtra("EXTRA_MESSAGE"); 
      Log.d("receiver", "Got message: " + message); 
     } 
    }; 

    @Override 
    protected void onDestroy() { 
     LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver); 
     super.onDestroy(); 
    } 

} 

ListenerService,方法onMessageReceived被解雇,在这里试图广播消息:

@Override 
public void onMessageReceived(MessageEvent messageEvent) { 
    super.onMessageReceived(messageEvent); 
    Log.d("tester", "received a message from wear: " + new String(messageEvent.getData())); 

    final String message = new String(messageEvent.getData()); 
    final Intent messageIntent = new Intent(); 
    messageIntent.putExtra("EXTRA_MESSAGE", message); // define your extra 
    LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent); 

} 

开始在AndroidManifest活动。 xml:

<activity android:name=".ReceiverActivity"> 
</activity> 

但是ReceiverActivity似乎没有收到消息,是否ReceiverActivity设置是否正确?

更新3:

按照意见,开始我加入活动:

Intent intent = new Intent(this, ReceiverActivity.class); 
    startActivity(intent); 

MainActivity.onCreate

@Override 
    protected void onCreate(Bundle savedInstanceState) { 

     super.onCreate(savedInstanceState); 

     Intent intent = new Intent(this, ReceiverActivity.class); 
     startActivity(intent); 
     ...... 
+0

我在这[博客]研究发现(http://android-developers.blogspot.com/2016/04/deprecation-of-bindlistener.html),在Android的磨损最好的做法是使用在AndroidManifest.xml中监听必须启动服务的事件。例如,如果您的手表应用程序需要将交互式消息或数据发送到手机。 – KENdi

+0

另外,在Live监听器部分中声明,您可以使用'addListener()'实时监听器,这些监听器仅在活动或服务运行时处于活动状态,否则不会影响设备。如果您想对活动中的功能进行实时状态更新,但没有进一步的背景影响,此功能特别有用。通常,您应该尝试使用'addListener()',并且只有在需要始终接收事件时才使用AndroidManifest.xml。希望它可以帮助你。 – KENdi

+0

@KENdi你可以提供一个使用addListener()的例子吗? –

回答

2
new ListenerService(); 

这不是你如何启动任何服务。这只是创建一个Servie实例,它不会做任何事情,并会在onCreate()退出后收集。

当您收到消息时,系统将启动此服务。您只需要在清单中定义它。此外,您可能需要为收到的消息定义路径,例如

<service android:name=".ListenerService" > 
    <intent-filter> 
     <action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED" /> 
     <data android:scheme="wear" android:host="*" android:pathPrefix="/message"/> 
    </intent-filter> 
</service> 

这就是您设置服务所需的全部内容。另外,请记住,为了接收消息,Wear应用程序和Handheld应用程序应该具有相同的包名称(applicationId)。仔细检查一下,您没有与flavor或buildTypes不匹配的applicationId。所以,如果你的build.gradle都的applicationID,确保它们匹配兼具耐磨和handhelp应用项目

defaultConfig { 
    applicationId "com.runner" 

关于更新UI:

@Override 
public void onMessageReceived(MessageEvent messageEvent) { 
    MainActivity.mTextView.setText("got message"); 
} 

这不是互动与活动相关的服务的方式。 服务运行时,活动可能会或可能不会运行。只从活动更新活动用户界面。如果您需要向用户显示消息,请使用BroadcastReceiverObserver

请注意,onMessageReceived()将不会在Main UI线程上运行,因此在使用Handler之前在那里显示Toast

所以,如果你想从本服务活动传递消息,途径之一是像

@Override 
public void onMessageReceived(MessageEvent messageEvent) { 
    final byte[] data = messsageEvent.getData(); 
    if (data != null) { 
     final String message = new String(data, Charset.forName("UTF-8")); 
     final Intent messageIntent = new Intent("custom-event-name"); 
     intent.putExtra(EXTRA_MESSAGE, message); // define your extra 
     LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent); 
     // Register BroadcastReiver from LocalBroadcastManager in your Activity to receive this broadcast 
    } 
} 

或者,如果你想开始活动,如果它没有运行,你需要一个不同的方法:

<activity 
    android:name=".ReceiverActivity" 
    android:launchMode="singleTop"/> 

服务:

@Override 
public void onMessageReceived(MessageEvent messageEvent) { 
    final byte[] data = messsageEvent.getData(); 
    if (data != null) { 
     final String message = new String(data, Charset.forName("UTF-8")); 
     final Intent activityIntent = new Intent(this, ReceiverActivity.class); 
     intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
     intent.putExtra("EXTRA_MESSAGE", message); 
     startActivity(intent); 
    } 
} 

// In this case, in Activity, if it's explicitly started, you don't need a BroadcastReceiver 
// Instead, you can get the extra from Activity Intent 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    handleIntent(getIntent()); 
} 

@Override 
protected void onNewIntent(Intent intent) { 
    super.onNewIntent(intent); 
    handleIntent(intent); 
} 

private void handleIntent(Intent intent) { 
    String message = intent.getStringExtra("EXTRA_MESSAGE"); 
} 

在耐磨部件

initApi(); 
sendToast(); 

您使用不同的线程可能同时运行,所以当sendToast()运行时,您可能实际上已经有nodeId尚未解决。

我建议的做法是将GoogleApiClient in onCreate()与Listener连接起来。一旦客户端连接,开始获取节点。 作为拉杰什在评论中提到的,Wearable.API被弃用:你并不需要生成你自己的线程,如果你使用的setResultCallback()代替await()

编辑14/02/2018的API是异步的。下面的答案指的是旧的API,这在写作时是新的。我现在正在离开旧的答案,但我没有时间研究如何使用新API做到这一点。

private static final String MESSAGE_PATH = "/message"; 

private GoogleApiClient googleApiClient; 

@Override 
protected void onCerate(Bundle state) { 
    super.onCreate(state); 
    googleApiClient = getGoogleApiClient(this); 
    googleApiClient.connect(); 
} 

@Override 
protected void onDestroy() { 
    super.onDestroy(); 
    googleApiClient.disconnect(); 
} 

private GoogleApiClient getGoogleApiClient(Context context) { 
    return new GoogleApiClient.Builder(context) 
      .addApi(Wearable.API) 
      .addConnectionCallbacks(mConnectionCallbacks) 
      .build(); 
} 

private void findNodes() { 
    Wearable.NodeApi.getConnectedNodes(googleApiClient).setResultCallback(
      new ResultCallback<NodeApi.GetConnectedNodesResult>() { 
       @Override 
       public void onResult(
         @NonNull final NodeApi.GetConnectedNodesResult getConnectedNodesResult) { 
        List<Node> nodes = result.getNodes(); 
        if (nodes != null && !nodes.isEmpty()) { 
         nodeId = nodes.get(0).getId(); 
         Log.d(TAG, "nodeId "+ nodeId); 
         onNodeFound(); 
        } 
       } 
      }); 
} 

private void onNodeFound() { 
    if (nodeId != null) { 
     // Now you have your node, send a message, make sure the path starts like the path in manifest 
     // What you thought is a message is actually a path, and the actual message is the byte array. 
     // You may concat your message in path though, but keep in mind you will have to parse the string then 
     Wearable.MessageApi.sendMessage(client, nodeId, MESSAGE_PATH, "Hello Wear!".getBytes(Charset.forName("UTF-8"))); 
    } 
} 

private final GoogleApiClient.ConnectionCallbacks mConnectionCallbacks 
     = new GoogleApiClient.ConnectionCallbacks() { 

    @Override 
    public void onConnected(@Nullable final Bundle bundle) { 
     findNodes(); 
    } 

    @Override 
    public void onConnectionSuspended(final int i) { 
    } 
}; 
+0

的意图过滤器,谢谢,我试着添加一个消息监听器,但似乎没有收到消息,请参阅问题更新。 –

+0

@蓝天,你错了。通过使用BroadcastReceiver我打算将数据从Service传递到Activity,而不是将其注册到Manifest中的MESSAGE_RECEIVED。查看已更新答案中的广播片段。 –

+0

再次感谢,我认为它几乎完成。我已经添加了第二个更新问题,看来我没有正确设置ReceiverActivity? –