0

I am attempting to read a feed from a URL in the form of a JSON Object, and pass that feed to a Wearable device to display as a list using the Data API. This JSON Object contains an array of objects, each object containing a few elements. Something like this:

{ "items":[
    { "title":"item 1", "element_1":"element 1", "element_2":"element 2" }
    { "title":"item 2", "element_1":"element 1", "element_2":"element 2" }
    { "title":"item 3", "element_1":"element 1", "element_2":"element 2" }
]}

I can get these items into an ArrayList of objects using GSON, or Jackson (though I think I prefer GSON), but I do not know how I would be able to that ArrayList of objects to the wearable. From what I can tell, I cannot. I would like to know if there is a way to do this, or if not, some sort of best practices on how I should go about this? Should I just get the JSON as a string, pass the string to the wearable, and parse it afterwards? I do not know if this would be inefficient if the string were very large though, considering I do not know how large the list of JSON objects could get. Also I know it is possible to parse a string with GSON, but I do not know if this is inefficient as well.

Bryan
  • 14,756
  • 10
  • 70
  • 125
  • Should the wearable receive the complete list of items, or only part of them? – dragi Oct 29 '15 at 13:28
  • @helleye Yes, the complete list of items. – Bryan Oct 29 '15 at 13:33
  • You send data by spiting it as messages and send as message using the [MessageApi](http://developer.android.com/training/wearables/data-layer/messages.html) – krishnan muthiah pillai Oct 29 '15 at 14:11
  • @krishnan I think in my case this would be very inefficient, considering some of the items in the JSON array will be static for a period of time. From what I understand, the DataApi can store this data so that the wearable only pulls more data when the list is updated. The way I am currently achieving this is to have the wearable send a message to the handheld to update the data when it is opened, then the wearable listens for this update. If the data is unchanged, there is no strain on the wearable. If I am constantly sending messages, then the wearable is constantly using precious resources. – Bryan Oct 29 '15 at 14:17

2 Answers2

1

The general recommendations are to send to the wearable the minimum data it needs, and to make the maximum processing on the handheld device, as it has much more processing power (and battery).
According to the documentation: https://developers.google.com/android/reference/com/google/android/gms/wearable/DataItem.html#setData(byte[])
The current maximum data item size limit is approximtely 100k. Data items should generally be much smaller than this limit.
You should make the decision if this suits your needs - if it is possible to receive very big JSON, maybe you can split it on the handheld device side, or you can filter some of the data inside.

If you think that this would not be possible for your case, then maybe you should revise the requirements you have!


I am processing JSON using GSON directly on the wearable, and for my use-cases it is working good enough.

dragi
  • 3,385
  • 5
  • 22
  • 40
1

I found the Android Wear Sample XYZTouristAttractions, and this is my current code based on that example. Firstly, I created a shared library to reduce duplicate code. This shared library contains the Item class that holds the JSON data. I use this class in my DownloadArrayListTask on the handheld, which takes the JSON Object from the input stream and puts the data in an ArrayList of Item objects.

@Override
protected ArrayList<Item> doInBackground(URL... params) {
    URL url = params[0];
    ArrayList<Item> items = new ArrayList<>();

    try {
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        try {
            InputStreamReader input = new InputStreamReader(connection.getInputStream());

            Type listType = new TypeToken<Map<String, ArrayList<Item>>>(){}.getType();
            Gson gson = new GsonBuilder().create();
            Map<String, ArrayList<Item>> treeMap = gson.fromJson(input, listType);
            items = treeeMap.get("items");

            input.close();
        } finally {
            connection.disconnect();
        }
    } catch (IOException exception) {
        exception.printStackTrace();
    }

    return items
}

This ArrayList is broken apart into strings in the DataLayerListenerService and placed in an ArrayList of DataMap objects for the wearable to receive.

@Override
public void onMessageReceived(MessageEvent messageEvent) {
    GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this)
            .addApi(Wearable.API).build();

    ConnectionResult connectionResult = googleApiClient.blockingConnect(30, TimeUnit.SECONDS);
    if(!connectionResult.isSuccess()) {
        Log.e(TAG, "Failed to connect to Google API Client");
        return;
    }

    if(messageEvent.getPath().equals("/update_path") {
        ArrayList<Item> items = new ArrayList<>()
        try {
            items = new DownloadArrayListTask().execute(new URL("http://my_url")).get();
        } catch (MalformedURLException | InterruptedException | ExecutionException exception) {
            exception.printStackTrace();
        }

        ArrayList<DataMap> itemMaps = new ArrayList<>(items.size());

        for(Item item : items) {
            DataMap dataMap = new DataMap();
            dataMap.putString("title", item.getTitle());
            dataMap.putString("element1", item.getElement1());
            dataMap.putString("element2", item.getElement2());

            itemMaps.add(dataMap);
        }

        new Thread(new Runnable() {
            @Override
            public void run() {
                NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleApiClient).await();

                for(Node node : nodes.getNodes()) {
                    PutDataMapRequest dataMapRequest = PutDataMapRequest.create("/item_path");
                    dataMapRequest.getDataMap().putDataMapArrayList("item_key", itemMaps);

                    PutDataRequest request = dataMapRequest.asPutDataRequest();
                    DataApi.DataItemResult result = Wearable.DataApi.putDataItem(googleApiClient, request).await();

                    if(!result.getStatus().isSuccess()) {
                        Log.d(TAG, "Failed to send data");
                    }
                } 
            }
        }).start();
    }
}

Then the wearable device receives this ArrayList of DataMap objects, and uses its own AsyncTask to put them back into an ArrayList of Item objects.

@Override
protected ArrayList<Item> doInBackground(Uri... params) {
    Uri uri = params[0];
    ArrayList<Item> items = new ArrayList<>();

    GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this)
            .addApi(Wearable.API).build();

    ConnectionResult connectionResult = googleApiClient.blockingConnect(30, TimeUnit.SECONDS);
    if(!connectionResult.isSuccess()) {
        Log.e(TAG, "Failed to connect to Google API Client");
        return;
    }

    DataItemBuffer results = Wearable.DataApi.getDataItems(googleApiClient).await();

    if(results.getStatus().isSuccess() && results.getCount() != 0) {
        DataMapItem dataMapItem = DataMapItem.fromDataItem(results.get(0);

        List<DataMap> data = dataMapItem.getDataMap().getDataMapArrayList("item_key");

        for(DataMap dataItem : data) {
            Item item = new Item(dataItem.getString("title"),
                    dataItem.getString("element1"),
                    dataItem.getString("element2"));
            items.add(item);
        }
    } else {
        Log.d(TAG, "Failed to obtain data");
    } return items;
}
Bryan
  • 14,756
  • 10
  • 70
  • 125
  • Hey, a side question. What do you do with these items afterwards (on wear)? Do you store them in the local db or you somehow cause them to be re-delivered from handheld next time wear app is started? – Dennis K Nov 12 '15 at 22:11
  • @DennisK Currently I am sending a message to the handheld every time the app is started to re-sync the data. I have not tried to save to a local database because the information I am receiving is only relevant if it is current. You should be able to save it to a local database on the wearable, though I am not that familiar with the limitations of the wear platform. – Bryan Nov 13 '15 at 13:56