我尝试使用以下代码从可穿戴设备向移动设备发送字符串。 此实现基于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
来源:
移动组件
启动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中MessageListener的配置:
<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 :(得分: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应用程序和手持设备应用程序应具有相同的程序包名称(applicationId)。仔细检查你是不是有不匹配的applicationId for flavor或buildTypes。因此,如果您在build.gradle中有applicationId,请确保它们与wear和handhelp应用程序项目相匹配
defaultConfig {
applicationId "com.runner"
关于更新用户界面:
@Override
public void onMessageReceived(MessageEvent messageEvent) {
MainActivity.mTextView.setText("got message");
}
这不是将服务与Activity进行交互的方法。
Service运行时,Activity可能会也可能不会运行。仅从活动更新Activtity UI。如果您需要向用户显示消息,请使用BroadcastReceiver
或Observer
。
请注意,onMessageReceived()
线程不会运行Main UI
,因此在显示Handler
之前请先使用Toast
。
因此,如果您想将此服务中的消息传递给Activity,其中一种方法就像
@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
中的onCreate()
与监听器连接起来。客户端连接后,开始获取节点。您不需要生成自己的线程,如果您使用setResultCallback()
而不是await()
编辑14/02/2018 :正如Rajesh在评论中提到的,Wearable.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) {
}
};