Android synchronizing database with wearable - Dat

2019-07-12 13:18发布

问题:

I try to synchronize data from a SQLite database on the handheld to a wearable. Therefore I use the Data API with the following code on the handheld:

cursor.moveToFirst();
while (!cursor.isAfterLast()) {
    final PutDataMapRequest putRequest = PutDataMapRequest.create("/SAMPLE");
    putRequest.setUrgent();
    final DataMap map = putRequest.getDataMap();
    int i = 0;
    for (String columnName: cursor.getColumnNames()) {
        map.putString(columnName,cursor.getString(i));
        i++;
    }
    Wearable.DataApi.putDataItem(googleApiClient, putRequest
            .asPutDataRequest()).setResultCallback(new ResultCallback() {
                @Override
                public void onResult(Result result) {
                    if (!result.getStatus().isSuccess()) {
                        Log.v("MainActivity", "data could not be sent");
                    } else {
                        Log.v("MainActivity", "data sent");
                    }
                }
    });
    cursor.moveToNext();
}
cursor.close();

Then on the wearable I have a DataApi.DataListener to look for changes:

@Override
public void onDataChanged(DataEventBuffer dataEventBuffer) {
    for (DataEvent event : dataEventBuffer) {
        String data = null;
        try {
            data = new String(event.getDataItem().getData(), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        Log.v(TAG, "onDataChanged data: "+ data);

        if (event.getType() == DataEvent.TYPE_CHANGED && event.getDataItem().getUri().getPath().equals("/SAMPLE")) {

            DataMapItem item = DataMapItem.fromDataItem(event.getDataItem());
            String column1_value = item.getDataMap().getString(column1);

            Log.v(TAG, "onDataChanged column1: "+ column1_value);
        }
    }
}

This works well, I can send all rows of my database to the wearable and receive them there.

Now I read that it is not necessary to copy the data into a new SQLite database on the wearable but instead use directly the DataItembuffer which already has the data stored in an own database. e.g. How to use DataItem of Android Wear or Android Wear How Long do DataMap entries Stay Valid

But when I want to retrieve the previously synchronized data in a method later on, I get only one item from the 20 rows sent before, the last one. It seems to overwrite my items... But I would need of course all of them...

public void getDataItems(){
    final PendingResult<DataItemBuffer> results = Wearable.DataApi.getDataItems(googleApiClient);

    Runnable r = new Runnable() {
        @Override
        public void run() {
            DataItemBuffer dataItems = results.await();
            for (int i = 0; i < dataItems.getCount(); i++) {
                DataMapItem item = DataMapItem.fromDataItem(dataItems.get(i));

                String column1_value = item.getDataMap().getString(column1);
                Log.v(TAG, "getDataItems column1: "+ column1_value);
            }
        }
    };
    Thread thread = new Thread(r);
    thread.start();

    /*
    results.setResultCallback(new ResultCallback<DataItemBuffer>() {
        @Override
        public void onResult(DataItemBuffer dataItems) {
            Log.v(TAG, "dataItems length: "+ dataItems.getCount());
            for (int i = 0; i < dataItems.getCount(); i++) {

                DataMapItem item = DataMapItem.fromDataItem(dataItems.get(i));
                String column1_value = item.getDataMap().getString(column1);
                Log.v(TAG, "getDataItems column1: "+ column1_value);
            }
            dataItems.release();
        }
    });*/
}

There is obviously no difference between using await() and the ResultCallback, I always get only the last item...

What am I doing wrong here?

UPDATE: I noticed that it makes a difference if I use different URIs. If I use

final PutDataMapRequest putRequest = PutDataMapRequest.create("/SAMPLE1");

and

final PutDataMapRequest putRequest = PutDataMapRequest.create("/SAMPLE2");

then I get in the getDataItems method at least two items, but still just the last one for each URI. According to the Docs each DataItem is identified by one URI consisting usually of the node ID and the path. https://developers.google.com/android/reference/com/google/android/gms/wearable/DataItem As it seems to be ineffective using hundreds or thousands of paths, it's the question whether the DataItems can even replace a SQLite db or not...

Or is there a way having multiple DataItems under one URI?

回答1:

If you use the same "path" for multiple data items, you are effectively updating the data each time you put a new one with that paths so that explains why you get only the "last" update; if you want to have access and retrieve all individually, you need to use different path or use a different data structure (say, an array) for each path. Regardless, using the data storage provided by the DataApi as a replacement for sqlite database is not recommended; the DataLayer storage is designed with a different set of goals in mind so if you really want to store the data on the other end for running queries against, etc, you are better off to retrieve them from the Data storage and put them into your own sqlite database for the purpose you have in mind (and delete the items from the Data storage as you process them).