A weird one: app sporadically doesn't draw screen on startup.

Hi,

Hoping this one is something obvious.

I have an app that calculates a load of stuff, and reads settings, on start up then calls WatchUi.requestUpdate() and carries on...

Every now and then (often enough to be annoying, maybe one in 10) the app simply starts without drawing the screen.

No errors.

Everything works.

If I do _anything_ that would trigger a redraw, it recovers.

But it just starts with a black screen.

Any clues?

G

  • PS: I can reproduce this readily in the sim. If I add in a trace:

    function onUpdate(dc) {
    		System.println("ON UPDATE");

    I can see that onUpdate is called even when the screen doesn't show.

  • For now I have a nasty, nasty hack to fix it.

    var startupRedrawTimer;	
    function initialize() {
        View.initialize();
        reset();
    	startupRedrawTimer = new Timer.Timer();
    	startupRedrawTimer.start(method(:killStartupTimer), 500, true);
    }
    // Hack to make sure screen always drawn...
    function killStartupTimer() {
    	if(startupRedrawTimer != null) {
    		startupRedrawTimer.stop();
    		startupRedrawTimer = null;
    		// System.println("KILL TIMER");
    		WatchUi.requestUpdate();
    	}
    }

    But pretty sure I shouldn't need that.

  • There is someone weird in your app.  Depending on when you calculate everything you shouldn't need to call requestUpdate, as onUpdate will be called once after initialize() and onLayout() if you do nothing.  Do the initial stuff in initialize()/onLayout(), or maybe the first time in onUpdate is called before doing anything else.

    in your fix, if you make the last parameter to start false, it's then a one shot so you can remove most of killStartupTimer, but you really should need that timer at all.

  • you really should need that timer at all

    That's what I thought. Disappointed

    I've just had a thought, though: could it be the order of my initialize()?

    Should the "View.initialize()" be the last line instead of the first? 

  • Nope, first is fine.  The Ui.requestUpdate() could be part of the problem, as after initialize(), onUpdate() will be called already.

    Look at any of the device apps samples in the SDK.  In a device app or widget, that onUpdate() always occurs.  After that, you can use a timer to call Ui.requestUpdate(), or based on something happening (position callback, sensor callback, onBackgroundData, etc)

  • I have a requestUpdate() call as the last line of my reset() method - so it is always called.

    Are you saying I should take that out as it isn't necessary here?

  • Yes.  or if it's used in other places, add a parameter to do it or not.

    This is a pretty basic thing in device apps - onUpdate will get called once by default as doing things as you are could confuse things..  As I said, try any device app in samples.  After that call requestUpdate only when you need to update the screen.  For many things, I use a timer for that - in others, a callback as I mentioned..

  • onUpdate will get called once by default as doing things as you are could confuse things

    Well...

    1. So I've taken out all of those things, and:
    2. Put in a println() for every requestUpdate
    3. Put in a println() for initialize, onUpdate and onLayout

    It appears to affect specific devices in the simulator more than others (735xt is reliably bad).

    When I run my app, after taking out everything, my console displays this:

    :>INIT
    LAYOUT
    UPDATE
    UPDATE

    And my simulator displays this roughly one in ten times:

    If I use the down arrow to get to the menu, it displays my menu and when I go back everything is correct.

  • Is it possible there is a race condition somewhere?

    I mean, the stuff I do in reset() is pretty mundane (read app.getProperty() and then do some sums).

    The app is clearly calling onUpdate, it just isn't... you know... reaching the screen.

  • Ok, I'm going to submit a bug report on this one.

    I can replicate it with minimal classes where the only code is System.println and a (very) simple onUpdate.