3

我正在开发一款可在可穿戴设备(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)
4

1 回答 1

1

看看 Github 项目SensorDashboard,他们接收所有传感器数据并通过MessageAPI. 我认为它运作良好。据我所知,他们使用某种上限来限制发送的数据量。

于 2015-02-17T14:31:15.487 回答