WinRT chyták – “one shot” Timer BackgroundTask se neodregistruje po jeho “one shot”

Nejprve – omlouvám všem fanouškům Jacka Reachera, tento článek není o jedné z knih této série, leč jeho název ji obsahuje rovnou dvakrát 🙂 .

V mé poslední vydané Windows 10 aplikaci Event Countdowns jsem udělal nešťastnou chybu. Při registraci Background Tasku který měl aktualizovat dlaždice aplikace každých 30 minut jsem použil následující kód:

string myTaskName = "TileUpdaterBackgroundTask";

// check if task is already registered
var task =
    BackgroundTaskRegistration.AllTasks.Where( cur => cur.Value.Name == myTaskName ).Select( c => c.Value ).SingleOrDefault();
if ( task != null )
{
    //do not register again                    
    return;
}

var backgroundAccess = await BackgroundExecutionManager.RequestAccessAsync();

if ( backgroundAccess == BackgroundAccessStatus.AllowedMayUseActiveRealTimeConnectivity ||
    backgroundAccess == BackgroundAccessStatus.AllowedWithAlwaysOnRealTimeConnectivity )
{
    // register a new task
    BackgroundTaskBuilder taskBuilder = new BackgroundTaskBuilder
    {
        Name = myTaskName,
        TaskEntryPoint = "TileUpdateTask.TileUpdateBackgroundTask"
    };

    taskBuilder.SetTrigger( new TimeTrigger( 30, true ) );

    BackgroundTaskRegistration myFirstTask = taskBuilder.Register();
}

Na první pohled nic neobvyklého. Nebo – to jsem si alespoň myslel. Den po vydání aplikace jsem se podíval na připnutou dlaždici odpočítávající čas do premiéry filmu Captain America: Civil War a s velkým překvapením zjistil, že zobrazený zbývající čas je byl o den posunutý! Okamžitě jsem zkontroloval zdrojový kód a po několika minutách zběsilého debugování jsem objevil skryté zlo – druhý parametr konstruktoru třídy TimeTrigger.

taskBuilder.SetTrigger( new TimeTrigger( 30, true ) );

Druhý parametr, oneShot, určuje, zda task bude spuštěn pouze jednou (hodnota true) nebo periodicky (hodnota false).

Moje naivní řešení tedy spočívalo ve výměně true za false a protože na počítači aplikace fungovala bez problémů, publikoval jsem aktualizovanou verzi na Store.

Když nová verze aplikace dorazila na můj telefon, s radostí jsem ji nainstaloval, spustil a čekal, až dlaždice znovu oživnou. A čekal jsem. A čekal jsem. A… nic.

Byl jsem zmaten a nechápal jsem, kde může být rozdíl mezi počítačem a telefonem. Tak jsem se znovu vrátil ke zdrojovému kódu a znovu jej promyslel. A pak – jsem to uviděl.

// check if task is already registered
var task =
    BackgroundTaskRegistration.AllTasks.Where( cur => cur.Value.Name == myTaskName ).Select( c => c.Value ).SingleOrDefault();
if ( task != null )
{
    //do not register again
    return;
}

Přirozeně jsem předpokládal, že jakmile oneShot Background Task je jednou spuštěn, systém jej automaticky odregistruje. Ve skutečnosti tomu tak ale není.

I poté co oneShot trigger spustí Background Task, task stejně zůstane zaregistrován!

To znamená, že po instalaci aktualizované verze aplikace na můj telefon a jejím spuštění se při pokusu o registraci tasku kód zastavil na kontrole podmínky task != null  která se vyhodnotila jako true, protože task byl stále zaregistrován, přestože již proběhl!

Finální řešení tedy vyžadovalo vynutit odregistrování Background Tasku a jeho znovuzaregistrování s oneShot nastaveným na false.

Bug je odchycen a dlaždice znovu žijí!

 

Buy me a coffeeBuy me a coffee

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.