Search code examples
androidandroid-servicewear-osandroid-broadcastreceiverandroid-intentservice

Custom broadcast receiver in CanvasWatchFaceService


I'm developing some watch faces for Android Wear (minSdkVersion=21 and targetSdkVersion=23) and integrating the Google Fit API for Android.

I want to poll in the background for fit data with a given - user selected - time interval and pass it back to my watch face. So I created a service which extends Service class, implements SensorEventListener, GoogleApiClient ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener etc, and I use the Fitness API to read fit data and heart sensor data.

I then pass the values back (Calories, Distance, Steps etc.) to the watch face, which is a standard class extending CanvasWatchFaceService, by using a custom BroadcastReceiver.

What I want to achieve is to have always updated fitness variables available in the watch face, so that when it leaves ambient or muted mode because a user interacts with it, the data I need to show is already there and I just need to draw it on the screen without the need to read it by using the Fitness API at that moment, since it can take several seconds.

And it works. Data is received by the broadcast receiver in the watch face and variable values are correctly set. I output them on the screen by using a simple canvas.drawText. I see them update in interactive mode (watch face visible and active), of course according with the polling time interval, and even see them update in ambient mode when onTimeTick is called, if I'm debugging the watch face (either via usb or bluetooth).

As soon as i disconnect the debugger and the watch face goes in ambient mode, it seems that messages simply stop being received by the broadcast receiver.

What am i doing wrong? I'm really getting frustrated at this.


Solution

  • The Android OS will kill a background Service as soon as it finishes processing; that's basic to its lifecycle. You can read more about this in the documentation.

    For your use case, you probably want to set up a BroadcastReceiver, and trigger it at your polling interval with AlarmManager.setExactAndAllowWhileIdle(). It might make sense to roll this into the existing BroadcastReceiver you already have in your WatchFaceService subclass, or you may want to create a new one to replace your polling Service.

    Also, I don't know how frequently you're polling, but doing this too often while the watch is asleep is likely to have a significant impact on battery life. Just something to keep in mind; you may want to do something like a gradual decrease in frequency when the watch has been asleep for a while.