0

I have an app where I would like to update the live tile when the user leaves the app. First question is if this is a bad idea? If the user starts the app 20 times per day will this be a bad idea or in any way affect the background service?

Second question is if there is a limit for how long or resource intensive this might be. I guess I will put this code in OnNavigatedFrom, will the OS kill the app if the updating of live tile takes too long? I need to create an image, save it to isolated storage, read the image and then update the tile.

Really looking forward to some thoughts from you on this.

EDIT 1: The reason for me asking is that if I do it like above it works just fine. But if I exit the app immediately when it starts up I only get a black tile instead of a tile with a background image. So I get the impression that the code doesn't finish. How can I avoid that?

EDIT 2: Since I'm creating my live tile dynamically I think the problem is the loading of the background image. I load a background image and then add text to it. When the tile goes black I can still see the text so there must be something with the loading of the background image that is used as background for the tile.

Edit 3:Here is the complete code for the creation of the image that is used as a background image. I tried to simplify it a little to reduce the code.

Grid grid = new Grid();

StackPanel sp = new StackPanel();
sp.Height = 173;
sp.Width = 173;

sp.Background = (SolidColorBrush)Application.Current.Resources["PhoneAccentBrush"];
strBackBackground = "";

StreamResourceInfo info;

sp.Background = (SolidColorBrush)Application.Current.Resources["PhoneAccentBrush"];
strBackBackground = "";
info = Application.GetResourceStream(new Uri("/MyApp;component/images/Icons/livetile/metro-" + strSymbol + ".png", UriKind.Relative));

// create source bitmap for Image control (image is assumed to be alread 173x173)
WriteableBitmap wbmp3 = new WriteableBitmap(1, 1);
try
{
    wbmp3.SetSource(info.Stream);
}
catch
{
}

Image img3 = new Image();
img3.Source = wbmp3;
// add Image to Grid
img3.Width = 173;
img3.Height = 173;
img3.Margin = new Thickness { Left = 0, Bottom = 0, Right = 0, Top = 0 };

TextBlock txtTemperature = new TextBlock();
TextBlock txtTemperatureRing = new TextBlock();

txtTemperature.Foreground = new SolidColorBrush(Colors.White);
txtTemperature.Text = strTemp;
txtTemperature.TextAlignment = TextAlignment.Right;
txtTemperatureRing.Style = (Style)Application.Current.Resources["PhoneTextTitle3Style"];
txtTemperatureRing.FontFamily = new FontFamily("Segoe WP Light");
txtTemperatureRing.FontSize = 40;
txtTemperatureRing.Foreground = new SolidColorBrush(Colors.White);
txtTemperatureRing.Text = "°";
txtTemperatureRing.TextAlignment = TextAlignment.Right;

txtTemperature.FontFamily = new FontFamily("Segoe WP");
txtTemperature.FontSize = 40;
txtTemperature.Margin = new Thickness { Left = 0, Bottom = 0, Right = 0, Top = -55 };
txtTemperature.Height = 80;
txtTemperature.Width = 135;
txtTemperatureRing.Margin = new Thickness { Left = 130, Bottom = 0, Right = 0, Top = -112 };
txtTemperatureRing.Height = 50;
txtTemperatureRing.Width = 29;

sp.Children.Add(img3);
sp.Children.Add(txtTemperature);
sp.Children.Add(txtTemperatureRing);

//call measure, arrange and updatelayout to prepare for rendering
sp.Measure(new Size(173, 173));
sp.Arrange(new Rect(0, 0, 173, 173));
sp.UpdateLayout();
grid.Children.Add(sp);

WriteableBitmap wbmp = new WriteableBitmap(173, 173);
wbmp.Render(grid, null);
wbmp.Invalidate();

//write image to isolated storage
string sIsoStorePath = @"\Shared\ShellContent\tile.png";
using (IsolatedStorageFile appStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
    //ensure directory exists
    String sDirectory = System.IO.Path.GetDirectoryName(sIsoStorePath);
    if (!appStorage.DirectoryExists(sDirectory))
    {
        appStorage.CreateDirectory(sDirectory);
    }

    using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(sIsoStorePath, System.IO.FileMode.Create, appStorage))
    {
        wbmp.SaveJpeg(stream, 173, 173, 0, 100);
    }
}


/// If application uses both PeriodicTask and ResourceIntensiveTask
if (task is PeriodicTask)
{

    ShellTile TileToFind = ShellTile.ActiveTiles.First();


    if (TileToFind != null)
    {
        StandardTileData NewTileData = new StandardTileData
        {
            BackgroundImage = new Uri("isostore:Shared/ShellContent/tile.png", UriKind.Absolute),
            Title = strTitle,
            Count = null,
            BackTitle = (string)settings["SelectedCityName"],
            BackBackgroundImage = new Uri(strBackBackground, UriKind.Relative),
            BackContent = strWind + Environment.NewLine + strPrecipitation
        };

        TileToFind.Update(NewTileData);
    }
}
John
  • 681
  • 1
  • 8
  • 20

4 Answers4

1

There is a way to avoid your problems.

User is closing the app using a "back" button, right? So you can take adventage of this.

Just add method to this event, it has to executed completly before an app is closed. In your MainPage() method type:

this.BackKeyPress += new EventHandler<System.ComponentModel.CancelEventArgs>((sender, e) =>
{
    blablablablabla - your code;
});
Andrzej
  • 23
  • 4
  • Cool, so this means that my code will allow to finish before the app is closed. How will it work if I click the Windows button to return to the phones start screen? – John May 07 '12 at 07:43
  • Nothing, this is event for back button, not Windows button. – Andrzej May 20 '12 at 09:46
0

There's no hard guide lines as to exactly how long you have to finish processing when your application is deactivated. If you look at section 5.2 of the Technical Certification Requirements it gives a few scenarios around time limits for responsiveness when exiting / restarting your application (Must launch within 5 seconds, be usable in 20 seconds). Not adhering to these requirements may prevent your application being certified. There is also a watchdog process which will terminate your code if it's not shut down within a certain time period (sorry, unable to find exact numbers here). You can see this in action if you purposely put a long running task - or even a Thread.Sleep() - in your launch page's constructor.

If you're creating the image locally (ie. There's no network calls) then unless it's a complex image you should have enough time to do what you're after. I have a similar requirement in my application but it requires a network call to fetch the image. As a result I launch the update task on application start so while the application is loading I can begin fetching the image and silently update it while the user is distracted by my application.

In regards to your image ending up black if you exit immediately - is this while your splash screen is still display? I believe that if your first page's constructor hasn't displayed yet the watchdog will behave slightly differently.

MrMDavidson
  • 2,705
  • 21
  • 20
  • Thanks for clearifying. Image is local. Problem is that if I go from my main panorama (where the tile is update in the code) into my settings page and then hit back button twice (exiting the application without first going back to main panorama view) I only get a black tile. So I get a feeling that it's all going to fast. If I exit the settings page, whait for a second and then exit my app it all works fine. So as I'm writing below I need to check that my background image is saved/loaded (I render it dynamically, I add text to the image and save it as a new image) before updating the live tile – John Mar 08 '12 at 11:39
  • Can you hook into one of the `Application` life cycle events? If it has to be done *after* launch use `Application_Closing`/`Application_Deactivated` although I'd still recommend doing it *at* launch (eg. `Application_Launching` / `Application_Activated). This also makes it explicit when handling re-activation vs fresh instance. – MrMDavidson Mar 08 '12 at 22:27
  • Hi, thanks for your help. The problem is that even if I do so I have noticed rare occasions when the tile goes black. But since I use a background image and then add text to it and I can see the text (when the tile goes black) the problem is related to loading the background image. So the solution here is to somehow check if the image is loaded properly. Just don't know how to do that. – John Mar 09 '12 at 08:02
  • Can you post the code that's actually updating your `ShellTile`? – MrMDavidson Mar 09 '12 at 12:17
  • Yes, I have updated the original post with the code. Thanks for looking at this. – John Mar 09 '12 at 12:35
  • Could just be a copy/paste error but I'm noticing that the `StandardTileData`'s `BackBackgroundImage` uses the un-initialised `strBackBackground` for its data. I'd suggest you verify this is getting populated somewhere. Also, if you chuck a break point here and run it in the emulator, do you have 100% success rate? That'll eliminate the watchdog concern. Another thing that might help; Have you considered using http://wp7tiletoolkit.codeplex.com/ to generate your tiles? – MrMDavidson Mar 09 '12 at 23:53
0

As a general rule, doing things when exiting an app is a bad idea. Can you not find another point (or points) within the general operation of the app that this coudl be done instead?

You haven't said how you're updating the tile back but if you're downloading images yourself, it's highly likley you won't be able to do this while exiting the app. Also the asynchrous request to get the image won't block the closing of the app while you wait for the response so it's likely that the request will just be aborted. Trying to block the closing of the app while you wait for the response would be a very bad idea and if it took more than a couple of seconds coudl lead to your app process being killed by the OS.

Matt Lacey
  • 65,560
  • 11
  • 91
  • 143
  • I'm downloading data and when done I could update the live tile. The background image is stored locally and is choosen depending on the downloaded data. So if downloaded data is "1" then 1.png is shown. This way the tile is updated everytime new data is downloaded. But I still run into occations when I get a black background. So somehow I need to by code determine if the image is saved/loaded without problems and only update the tile if the image is OK. Can you help me out with this, I think this would be the best solution to do it. – John Mar 08 '12 at 11:35
0

Try to update the tile at Application_Launching.

If you update it at Application_Activated, there must be a black screen when swithing quickly between start menu and main panorama. It doesn't work to update it at Application_Closing/Application_Deactivated either

Ivy
  • 1
  • 1