我正在开发一款可在可穿戴设备(Sony Smart Watch 3)和手持设备(Samsung S5)上运行的应用程序。
我想从手表连续感应加速度计和陀螺仪数据并将数据发送并保存到手持设备。
我想知道这是实现这一目标的最佳方法。目前我正在使用DataApi
.
由于加速度计和陀螺仪数据采样率足够高,并且可穿戴应用程序不断向手机发送数据,因此分配了过多的内存,然后被操作系统杀死。
这是手表上的活动:
public class MyActivity extends Activity implements SensorEventListener{
private TextView mTextView;
private TextView textViewGyro;
private SensorManager mSensorManager;
private GoogleApiClient mGoogleApiClient;
private String mNode;
private float x,y,z;
private float gx,gy,gz;
private final String TAG = MyActivity.class.getName();
private final float GAIN = 0.9f;
public static final float EPSILON = 0.000000001f;
String WEARABLE_DATA_PATH = "/wearable_data";
//String WEARABLE_GYROSCOPE_PATH = "/wearable_gyroscope";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
@Override
public void onLayoutInflated(WatchViewStub stub) {
mTextView = (TextView) stub.findViewById(R.id.text);
textViewGyro= (TextView) stub.findViewById(R.id.textgyro);
}
});
mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Wearable.API)
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
@Override
public void onConnected(Bundle bundle) {
Log.d(TAG, "onConnected");
Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).setResultCallback(new ResultCallback<NodeApi.GetConnectedNodesResult>() {
@Override
public void onResult(NodeApi.GetConnectedNodesResult nodes) {
if (nodes.getNodes().size() > 0) {
mNode = nodes.getNodes().get(0).getId();
Log.e("Wearable","Device found");
Log.e("Wearable",mNode);
}
}
});
}
@Override
public void onConnectionSuspended(int i) {
Log.d(TAG, "onConnectionSuspended");
}
})
.addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.d(TAG, "onConnectionFailed : " + connectionResult.toString());
}
})
.build();
}
@Override
protected void onResume() {
super.onResume();
Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL);
Sensor sensor1 = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
mSensorManager.registerListener(this, sensor1, SensorManager.SENSOR_DELAY_NORMAL);
mGoogleApiClient.connect();
}
@Override
protected void onPause() {
super.onPause();
mSensorManager.unregisterListener(this);
mGoogleApiClient.disconnect();
}
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
x = (x * GAIN + event.values[0] * (1 - GAIN));
y = (y * GAIN + event.values[1] * (1 - GAIN));
z = (z * GAIN + event.values[2] * (1 - GAIN));
if (mTextView != null) mTextView.setText(String.format("\n" + "Accelerometer Data: \nX : %f\nY : %f\nZ : %f\n",x, y, z));
DataMap dataMap = new DataMap();
dataMap.putLong("timestamp", new Date().getTime());
dataMap.putFloat("ax",x);
dataMap.putFloat("ay",y);
dataMap.putFloat("az",z);
new SendToDataLayerThread(WEARABLE_DATA_PATH, dataMap).start();
}
if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) {
gx = event.values[0];
gy = event.values[1];
gz = event.values[2];
float omegaMagnitude = (float)java.lang.Math.sqrt(gx*gx + gy*gy + gz*gz);
// Normalize the rotation vector if it's big enough to get the axis
// (that is, EPSILON should represent your maximum allowable margin of error)
if (omegaMagnitude > EPSILON) {
gx /= omegaMagnitude;
gy /= omegaMagnitude;
gz /= omegaMagnitude;
}
if (textViewGyro != null)
textViewGyro.setText(String.format("\nGyroscope Data: \nX : %f\nY : %f\nZ : %f\n", gx, gy, gz));
DataMap dataMap = new DataMap();
dataMap.putLong("timestamp", new Date().getTime());
dataMap.putFloat("gx",gx);
dataMap.putFloat("gy",gy);
dataMap.putFloat("gz",gz);
new SendToDataLayerThread(WEARABLE_DATA_PATH, dataMap).start();
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
class SendToDataLayerThread extends Thread {
String path;
DataMap dataMap;
// Constructor for sending data objects to the data layer
SendToDataLayerThread(String p, DataMap data) {
path = p;
dataMap = data;
}
public void run() {
NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).await();
for (Node node : nodes.getNodes()) {
// Construct a DataRequest and send over the data layer
PutDataMapRequest putDMR = PutDataMapRequest.create(path);
putDMR.getDataMap().putAll(dataMap);
PutDataRequest request = putDMR.asPutDataRequest();
DataApi.DataItemResult result = Wearable.DataApi.putDataItem(mGoogleApiClient,request).await();
if (result.getStatus().isSuccess()) {
Log.e("myTag", "DataMap: " + dataMap + " sent to: " + node.getDisplayName());
} else {
// Log an error
Log.e("myTag", "ERROR: failed to send DataMap");
}
}
}
}
}
我有以下异常和错误:
02-13 02:06:37.777 17349-17360/? E/DataBuffer? Internal data leak within a DataBuffer object detected! Be sure to explicitly call release() on all DataBuffer extending objects when you are done with them. (su@357af50)
02-13 02:24:09.300 594-685/? D/WearableService? putData: exception during processing: PutDataRequest[dataSz=67, numAssets=0, uri=wear:/wearable_gyroscope]
android.os.DeadObjectException
02-13 02:24:09.108 594-685/? D/WearableService? getConnectedNodes: exception during processing
android.os.DeadObjectException
android.system.ErrnoException: read failed: EAGAIN (Try again)
at libcore.io.Posix.readBytes(Native Method)
at libcore.io.Posix.read(Posix.java:147)
at libcore.io.BlockGuardOs.read(BlockGuardOs.java:230)
at android.system.Os.read(Os.java:364)
at com.android.server.am.NativeCrashListener.consumeNativeCrashData(NativeCrashListener.java:240)
at com.android.server.am.NativeCrashListener.run(NativeCrashListener.java:138)
02-13 15:46:29.977 150-150/? E/DEBUG? AM write failure (32 / Broken pipe)
02-13 15:46:34.704 21570-21581/? E/DataBuffer? Internal data leak within a DataBuffer object detected! Be sure to explicitly call release() on all DataBuffer extending objects when you are done with them. (su@35563df0)
02-13 11:14:44.482 12012-12012/? E/AndroidRuntime? FATAL EXCEPTION: main
Process: com.example.fazlay.accelerometerwearable, PID: 12012
java.lang.OutOfMemoryError: pthread_create (1040KB stack) failed: Try again
at java.lang.Thread.nativeCreate(Native Method)
at java.lang.Thread.start(Thread.java:1063)
at com.example.fazlay.accelerometerwearable.MyActivity.onSensorChanged(MyActivity.java:168)
at android.hardware.SystemSensorManager$SensorEventQueue.dispatchSensorEvent(SystemSensorManager.java:405)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:143)
at android.os.Looper.loop(Looper.java:122)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
02-13 15:52:47.934 424-464/? E/ActivityManager? ANR in com.example.fazlay.accelerometerwearable (com.example.fazlay.accelerometerwearable/.MyActivity)
PID: 0
Reason: Input dispatching timed out (Waiting to send non-key event because the touched window has not finished processing certain input events that were delivered to it over 500.0ms ago. Wait queue length: 6. Wait queue head age: 13150.8ms.)
02-13 16:19:23.999 24797-24797/? E/AndroidRuntime? FATAL EXCEPTION: main
Process: com.example.fazlay.accelerometerwearable, PID: 24797
java.lang.IllegalStateException: await must not be called on the UI thread
at com.google.android.gms.internal.jx.a(Unknown Source)
at com.google.android.gms.common.api.BaseImplementation$AbstractPendingResult.await(Unknown Source)
at com.example.fazlay.accelerometerwearable.MyActivity.onSensorChanged(MyActivity.java:171)
at android.hardware.SystemSensorManager$SensorEventQueue.dispatchSensorEvent(SystemSensorManager.java:405)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:143)
at android.os.Looper.loop(Looper.java:122)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)