2

I'm using the Data API in a service for Android Wear in a watch face that pulls down data from the cloud in a phone app and syncs it through a DataMap to the paired watch app. But I'm a bit lost on how to get the service on the wearable side to properly listen to updates AND redraw its UI. Should I be doing this all from the same service?

I tried implementing the DataApi.DataListener methods in the private internal class that extends CanvasWatchFaceService.Engine, but that doesn't seem to work.

@Override
    public Engine onCreateEngine() {
        return new Engine();
    }

    private class Engine extends CanvasWatchFaceService.Engine implements DataApi.DataListener {

       // other events and methods...    

        @Override
        public void onDataChanged(DataEventBuffer dataEvents) {
            for(DataEvent event : dataEvents) {
                DataItem dataItem = event.getDataItem();
                if(PATH.equals(dataItem.getUri().getPath())) {
                    DataMap dataMap = DataMapItem.fromDataItem(dataItem).getDataMap();
                    downloadedTrends = dataMap.getString(DATAMAP_KEY);
                }
            }
        }

       @Override
       public void onDraw(Canvas canvas, Rect bounds) {
          // use the changed data here to update the watch face UI
       }
    }

Should I be using a separate service extending WearableListenerService, and if so, how do I extract the data in onDraw in the watch face service? Can I tap the DataEventBuffer directly outside of the callback?

I'm also think it might have something to do with the BIND_LISTENER intent filter in the manifest, since I'm implementing it on the private internal class.

Thanks for your help!

user2302078
  • 142
  • 1
  • 11

3 Answers3

1

You should separate these two services. Watch face services draws the watch face, data api service handles data item changes.

Now, you need to somehow connect them. There are several ways. I will start with the practical, very ugly one: your data api service has a public, static interface, through which other components can register "listeners" and get information about data changes. As long as you are in the same process, everything is fine. When your watch face engine is create, it registers itself as a listener and when it's destroyed, it deregisters itself.

There are alternatives. Your data api service can send broadcasts, when it receives a new data item and the watch face can listen for them. It can either include the data inside or you can have a content provider backed by data items (in this case, the content provider would receive a broadcast from the data api service and the watch face would have a content observer on that provider).

Does any of these approaches suit your needs?

gruszczy
  • 40,948
  • 31
  • 128
  • 181
1

While having separate service could definitely fit the bill, I was researching for possibly having just one service for both CanvasWatchFaceService and being registered for Data Layers API, and seems the DigitalWatchFaceService in the Google sample/android-WatchFace provide an example of this.

Notice it provide example to register both as BroadcastReceiver AND the Data API.

Hope this helps.

https://github.com/googlesamples/android-WatchFace/blob/master/Wearable/src/main/java/com/example/android/wearable/watchface/DigitalWatchFaceService.java

tarilabs
  • 2,178
  • 2
  • 15
  • 23
0

I used a separate service to listen for dataitem changes. From there, I used SharedPreferences to store the data and recall it in my Draw method.

public class DataLayerService extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks,
    GoogleApiClient.OnConnectionFailedListener {
@Override
public void onDataChanged(DataEventBuffer dataEvents) {
    SettingsManager sm = new SettingsManager(getApplicationContext()); 
 //This is an interface for SharedPreferences I built for convenience
 DataMap dm = DataMap.fromByteArray(d.getDataItem().getData());
 sm.setString("WP_ICON", dm.getString("Icon"));
}
}

This code basically gets data from a phone and saves it locally.

private class Engine extends CanvasWatchFaceService.Engine {
    @Override
    public void onDraw(Canvas canvas, Rect bounds) {
        Drawable weather = getDrawable(getIcon(sm.getString("WP_ICON")));
        //The getIcon method chooses a Drawable based on the string. 
        //The values are from a set list
   }
}

It's a basic overview of how I did this from the watch side. This works pretty well functionality wise. Without a paired device it won't have any data issues as it's already offline.

Nick Felker
  • 11,536
  • 1
  • 21
  • 35