0

Has anyone got any idea why I'm getting an OutOfMemoryException when I'm creating my custom tile?

I'm trying to create custom images for my primary tile on a windows phone 8 app from a ScheduledAgent. The error doesn't occur until my very last line of code is executed which is the NotifyComplete().

Here is the code (Not the cleanest but ok for prototyping I guess). This code only handles the wide tile and it tries to load an image an image downloaded from a website and then it tries to render a logo and a description over this image.

Here is the code:

    private void CreateTiles()
    {
        Deployment.Current.Dispatcher.BeginInvoke(() =>
        {
            for (int i = 0; i < 2; i++)
            {
                var bmp = new WriteableBitmap(691, 336);
                var articleImg = new BitmapImage(new Uri(articles[i].ImageFilename, UriKind.Relative));
                var articleImage = new Image { Source = articleImg };
                articleImage.Stretch = Stretch.UniformToFill;
                articleImg.CreateOptions = BitmapCreateOptions.None; // Force the bitmapimage to load it's properties so the transform will work

                var bmpLogo = new WriteableBitmap(100, 100);
                var logoImg = new BitmapImage(new Uri("/Assets/Tiles/FlipCycleTileSmall.png", UriKind.Relative));
                var logoImage = new Image { Source = logoImg };
                logoImage.Opacity = 1.0;
                logoImg.CreateOptions = BitmapCreateOptions.None; // Force the bitmapimage to load it's properties so the transform will work

                var articleBannerGrid = new Grid();
                articleBannerGrid.Background = ColorExtensions.ToSolidColorBrush("#000F558E");
                articleBannerGrid.Opacity = .5;
                articleBannerGrid.Height = 100;
                articleBannerGrid.VerticalAlignment = VerticalAlignment.Bottom;
                articleBannerGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(100) });
                articleBannerGrid.ColumnDefinitions.Add(new ColumnDefinition());
                articleBannerGrid.Children.Add(logoImage);

                Grid.SetColumn(logoImage, 0);

                var textBlock = new TextBlock();
                textBlock.Text = articles[i].Description;
                textBlock.FontWeight = FontWeights.Bold;
                textBlock.Margin = new Thickness(10, 5, 30, 5);
                textBlock.TextWrapping = TextWrapping.Wrap;
                textBlock.Foreground = new SolidColorBrush(Colors.White); //color of the text on the Tile
                textBlock.FontSize = 30;
                textBlock.Opacity = 1.0;

                var articleTextGrid = new Grid();
                articleTextGrid.Height = 100;
                articleTextGrid.VerticalAlignment = VerticalAlignment.Bottom;
                articleTextGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(100) });
                articleTextGrid.ColumnDefinitions.Add(new ColumnDefinition());
                articleTextGrid.Children.Add(textBlock);

                Grid.SetColumn(textBlock, 1);

                var canvas = new Grid();
                canvas.Width = articleImg.PixelWidth;
                canvas.Height = articleImg.PixelHeight;
                canvas.Children.Add(articleImage);
                canvas.Children.Add(articleBannerGrid);
                canvas.Children.Add(articleTextGrid);

                bmp.Render(canvas, null);
                bmp.Invalidate(); //Draw bitmap

                FileStream fs = new FileStream(articles[i].ImageFilename, FileMode.Create);
                bmp.SaveJpeg(fs, bmp.PixelWidth, bmp.PixelHeight, 0, 100);
                fs.Close();
                fs.Dispose();
                articleImage = null;
                articleImg = null;
            }

            //GC.Collect();
            //GC.WaitForPendingFinalizers();

            ShellTile TileToFind = ShellTile.ActiveTiles.FirstOrDefault();

            if (TileToFind != null)
            {
                string title = articles[0].Tag;
                string backTitle = articles[1].Tag;
                string content = articles[0].Description;
                string backContent = articles[1].Description;

                FlipTileData tileData = new FlipTileData()
                {
                    Title = title,
                    BackTitle = backTitle,
                    BackContent = backContent,
                    WideBackContent = backContent,
                    BackgroundImage = new Uri(articles[0].ImageFilename, UriKind.Relative),
                    BackBackgroundImage = new Uri(articles[1].ImageFilename, UriKind.Relative),
                    WideBackgroundImage = new Uri(articles[0].ImageFilename, UriKind.Relative),
                    WideBackBackgroundImage = new Uri(articles[1].ImageFilename, UriKind.Relative),
                };

                TileToFind.Update(tileData);
            }

            NotifyComplete();

        });
    }

I assume that it is the correct place to generate the custom tile i.e. ScheduledAgent.

I found an article Dynamic Live Tile issue WP8 [WriteableBitmap] on the Nokia website with the same problem but no solution there either.

I'll continue debugging this tomorrow by removing everything and adding each bit individually step by step to see if I can spot anything but if anyone has got any suggestion or solution, I'd appreciate if you could help.

If I'm going about it the wrong way, please let me know what's the best method to update tiles in the scheduled agent.

Thanks.

Thierry
  • 6,142
  • 13
  • 66
  • 117

2 Answers2

2

WP BackgroundAgents have a small memory cap. 20MB for WP8 without update 3 and 25 for WP8 with Update 3.

I would suggest that you create a another project and add Coding4Fun toolkit and MemoryCounter in to your page and then add the code in your BackgroudAgent to the sample page and try to create the tiles. Then look at how much memory it uses. I think amount of memory usage is higher than the 20/25MB cap. if so you have to find a way to reduce it.

Kasun Kodagoda
  • 3,956
  • 5
  • 31
  • 54
  • Thanks for feedback. I'll give that a shot later if I'm still stuck but for now, I'll just update my answer. – Thierry Aug 07 '14 at 23:49
0

As usual, Microsoft is omitting critical information from its documentation.

After reducing the size of my tile from 691x336 to 336x165, it worked, so it got me thinking and I thought that the size recommended by Microsoft in this article Flip Tile template for Windows Phone 8 for wp8 and wp8.1 seemed excessive, so I did a bit more research and this is when I found this excellent explanation in an article in stackoverflow i.e.

Windows Phone 8 Startscreen Tile sizes and margins

This clearly states the size of the tiles but not based on OS versions but based on screen resolutions.

In my test environment, I was using the default 'Emulator WVGA 512MB' and again by default the screen size is 480x800, so taking into account the information provided in the answer of this article, my tile size should have been 430x210.

I resized my (already reduced) tile back up to 430x210, and it still worked.

While there is a memory cap of 20/25Mb depending on OS and patch being used, which probably causes many problems from the various articles I've read on the web, in my instance I believe it was more likely to have been affected by tile size being incorrect, and therefore the additional memory, or lack thereof.

I will update this article once I get to using 8.1 in my IDE with a larger resolution but for now, I have to assume that it was definitely related to the size of my tile.

I'll definitely make sure to add code to create tile based on os, patch and resolution being used. Bit of a pain to best honest!

Hope this helps.

Community
  • 1
  • 1
Thierry
  • 6,142
  • 13
  • 66
  • 117