Search code examples
wear-osandroid-wear-data-api

Realtime data exchange between Android Wearable and Handheld


I am working on a simple app which will run on both wearable(Samsung Gear Live) and handheld(Moto G). I want to display the data from the wearable's heart rate sensor, accelerometer and gyroscope on the handheld. Which is the best way to achieve this. Now I am using DataApi, but since I am updating data each second, it is allocating too much memory, and then killed by OS. Here is my service which runs on the wearable

public class SensorDataListener extends Service implements SensorEventListener,
        ConnectionCallbacks, OnConnectionFailedListener {
    private static final String TAG = SensorDataListener.class.getSimpleName();

    private static final int TIMEOUT_HEART_RATE    = 1000000;
    private static final int TIMEOUT_ACCELEROMETER = 1000000;
    private static final int TIMEOUT_GYROSCOPE     = 1000000;

    private static final String PATH_SENSOR_DATA = "/sensor_data";
    private static final String KEY_HEART_RATE = "heart_rate";

    private static final String KEY_ACC_X = "acc_x";
    private static final String KEY_ACC_Y = "acc_y";
    private static final String KEY_ACC_Z = "acc_z";

    private static final String KEY_GYRO_X = "gyro_x";
    private static final String KEY_GYRO_Y = "gyro_y";
    private static final String KEY_GYRO_Z = "gyro_z";

    private SensorManager mSensorManager;
    private Sensor mAccelerometer;
    private Sensor mGyroscope;
    private Sensor mHeartRate;

    private int mCurHeartRateVal;
    private float[] mCurAccelerometerVal = new float[3];
    private float[] mCurGyroscopeVal = new float[3];

    private GoogleApiClient mGoogleApiClient;
    ScheduledExecutorService mUpdateScheduler;

    ScheduledExecutorService scheduler;


    @Override
    public void onCreate() {
        super.onCreate();

        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addApi(com.google.android.gms.wearable.Wearable.API)
                .build();
        mGoogleApiClient.connect();

        mSensorManager = ((SensorManager)getSystemService(SENSOR_SERVICE));

        mHeartRate     = mSensorManager.getDefaultSensor(Sensor.TYPE_HEART_RATE);
        mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        mGyroscope     = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);

        startDataUpdated();
    }


    private void startDataUpdated() {
        scheduler = Executors.newSingleThreadScheduledExecutor();

        scheduler.scheduleAtFixedRate
                (new Runnable() {
                    public void run() {
                        updateData();
                    }
                }, 5, 3, TimeUnit.SECONDS);
    }


    private void updateData() {
        PutDataMapRequest dataMap = PutDataMapRequest.create(PATH_SENSOR_DATA);
        dataMap.getDataMap().putInt(KEY_HEART_RATE, mCurHeartRateVal);

        dataMap.getDataMap().putFloat(KEY_ACC_X, mCurAccelerometerVal[0]);
        dataMap.getDataMap().putFloat(KEY_ACC_Y, mCurAccelerometerVal[1]);
        dataMap.getDataMap().putFloat(KEY_ACC_Z, mCurAccelerometerVal[2]);

        dataMap.getDataMap().putFloat(KEY_GYRO_X, mCurGyroscopeVal[0]);
        dataMap.getDataMap().putFloat(KEY_GYRO_Y, mCurGyroscopeVal[1]);
        dataMap.getDataMap().putFloat(KEY_GYRO_Z, mCurGyroscopeVal[2]);

        PutDataRequest request = dataMap.asPutDataRequest();
        Wearable.DataApi.putDataItem(mGoogleApiClient, request);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        mSensorManager.registerListener(this, mHeartRate, TIMEOUT_HEART_RATE);
        mSensorManager.registerListener(this, mAccelerometer, TIMEOUT_ACCELEROMETER);
        mSensorManager.registerListener(this, mGyroscope, TIMEOUT_GYROSCOPE);

        return START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        Log.d(TAG, "onDestroy");
        mGoogleApiClient.disconnect();

        scheduler.shutdown();
        mSensorManager.unregisterListener(this);

        //mUpdateScheduler.shutdownNow();
        super.onDestroy();
    }    

    @Override
    public void onSensorChanged(SensorEvent event) {

        switch(event.sensor.getType()) {
            case Sensor.TYPE_HEART_RATE:
                if(event.values[0] <= 0) // HR sensor is being initialized
                    return;
                mCurHeartRateVal = Float.valueOf(event.values[0]).intValue();
                break;

            case Sensor.TYPE_ACCELEROMETER:
                mCurAccelerometerVal[0] = event.values[0];
                mCurAccelerometerVal[1] = event.values[1];
                mCurAccelerometerVal[2] = event.values[2];
                break;

            case Sensor.TYPE_GYROSCOPE: {
                mCurGyroscopeVal[0] = event.values[0];
                mCurGyroscopeVal[1] = event.values[1];
                mCurGyroscopeVal[2] = event.values[2];
                break;
            }
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {}

    @Override
    public void onConnected(Bundle bundle) { Log.d(TAG, "onConnected"); }

    @Override
    public void onConnectionSuspended(int i) { Log.d(TAG, "onConnectionSuspended"); }


    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) { Log.d(TAG, "onConnectionFailed"); }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

Solution

  • Try using the Message API instead of the Data API. Simply create a message containing your data and send it over to your other device : http://developer.android.com/reference/com/google/android/gms/wearable/MessageApi.html