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

Efficient Way To Get JSON Data To Wearable


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.


Solution

  • 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;
    }