1

I'm developing a watchface for Android Wear using the WatchFace API (extending CanvasWatchFaceService).

I've used the code from here to build a ticker that run code every second.

I'm experiencing the following problem. Every now and then the service crashes with this exception. I can't understand where it comes from, if you have any lead I'll post additional code.

01-06 11:22:00.247  12965-12965/com.my.package E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.my.package, PID: 12965
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.os.PowerManager$WakeLock.acquire()' on a null object reference
        at android.support.wearable.watchface.WatchFaceService$Engine.onCommand(WatchFaceService.java:201)
        at android.service.wallpaper.WallpaperService$Engine.doCommand(WallpaperService.java:977)
        at android.service.wallpaper.WallpaperService$IWallpaperEngineWrapper.executeMessage(WallpaperService.java:1191)
        at com.android.internal.os.HandlerCaller$MyHandler.handleMessage(HandlerCaller.java:37)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5221)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

After this crash the watchface stops working and to make it start again I have to choose another watchface, then reselect mine, so it's a total show stopper!

David Corsalini
  • 7,958
  • 8
  • 41
  • 66
  • are you calling `acquire()` method in `WatchFaceService`? – ρяσѕρєя K Jan 06 '15 at 10:37
  • Could you please post your code? Somewhere you invoked the `acquire()` method of a WakeLock object which is not initialized. On the site you referenced, no such thing happens. – UeliDeSchwert Jan 06 '15 at 10:37
  • Neither in my code, I also never use a WakeLock object. I'm using an ObjectAnimator, could it be the cause? – David Corsalini Jan 06 '15 at 10:48
  • I'm getting this same crash. Like you, my code never uses a WakeLock, and mine has no animators either. – Sterling Jan 11 '15 at 05:00
  • FWIW, I've opened a bug report for this issue, at https://code.google.com/p/android/issues/detail?id=95740 . Please star. – Sterling Jan 11 '15 at 17:16
  • Have you checked you have all the needed super.method(). I didn't have it on some methods and that was causing the crash. – David Corsalini Jan 12 '15 at 09:06
  • David, I have now, and that was indeed the problem. I've added an answer to this question with my specific finding, though it's really your solution (if you'd rather write it up yourself for the mojo). – Sterling Jan 12 '15 at 17:06

2 Answers2

4

Props to David for the lead on super. calls - it turns out that was the problem. Specifically, the CanvasWatchFaceService.Engine.onCreate method needs to call through to its ancestor, as such:

private class Engine extends CanvasWatchFaceService.Engine {

    @Override
    public void onCreate(SurfaceHolder holder) {
        super.onCreate(holder);
        // your engine initialization code here
    }

    // other watch face engine code
}

Without the super.onCreate(holder); call, my watch face would crash within minutes; with it, it happily ran overnight.

As an aside, this is something missing from the Android developer documentation; specifically, the Training page for Building a Watch Face Service doesn't include this ancestor call in its code sample.

Sterling
  • 6,365
  • 2
  • 32
  • 40
  • 1
    I have submitted a request to get the documentation https://developer.android.com/training/wearables/watch-faces/service.html#CallbackMethods changed. Thanks for the feedback! – Wayne Piekarski Jan 12 '15 at 20:41
  • I dug into the sample watch face code, as the docs suggest. That's when I realized I too was missing calls to super. – worked Jan 15 '15 at 15:23
0

The code you linked lacks some important parts, that are dotted. I.e. have you defined the update rate?

private static final long INTERACTIVE_UPDATE_RATE_MS = TimeUnit.SECONDS.toMillis(1);

Fully implemented it works well. See AnalogWatchFaceService in code samples: Wearable/Watchface face.

Piotr Miller
  • 311
  • 2
  • 12