RSS
 

Posts Tagged ‘Tombstoning’

Windows Phone 7 Image caching on Tombstoning

07 Nov

A recent Windows Phone 7 project had me wanting to cache a Silverlight Image object data on tombstoning.  The reason for this is when the user returned to the page there would be a delay before the image was shown because it was out pulling the image from data connection sources.  I wanted the images to show immediately when returned.  Upon looking for solutions for this issue I was surprised at what little, if any, information I could find directly related to it.  I present a solution to loading and caching this data in Windows Phone 7.

For the Image object I define it in XAML simply as:

<Image x:Name="CachedImage"
       ImageOpened="CachedImage_ImageOpened"/>

 

Note there is no source defined for this image object.  Without any code behind it will load nothing.  Initially I setup the MainPage constructor to load up the image directly from a URI as show here:

public MainPage()
{
    InitializeComponent();

    Uri u =
      new Uri("http://antwrp.gsfc.nasa.gov/apod/image/0806/saturn6_cassini_big.jpg",
              UriKind.Absolute);
    CachedImage.Source = new BitmapImage(u);
}

 

This will now allow the Image object to download and show the picture.  The problem with this is each and every time we go to this page it has to redownload the image data.  The goal is to now cache this data so if the user locks the screen or hits the search button then back again, that it doesn’t have to download the entire image off of the data connection.  Upon completion the ImageOpened event is fired, this is were we want to cache the data into the state.

private void CachedImage_ImageOpened(object sender, RoutedEventArgs e)
{
    Image i = (Image)sender;

    WriteableBitmap wbm = new WriteableBitmap(i, null);

    IDictionary<string, object> state = PhoneApplicationService.Current.State;
    state["ImageCache"] = _GetSaveBuffer(wbm);
}

 

The _GetSaveBuffer is a helper method that changes a WriteableBitmap to a Byte array, it is taken from Jeremy Likness’s blog on saving bitmaps to isolated storage in Silverlight 3.  So now this image is in the transient application state.  We now need to determine on load of the page to either load from cache or load from the URI.  Our page constructor now looks like this:

public MainPage()
{
    InitializeComponent();

    bool DownloadImage = true;

    try
    {
        IDictionary<string, object> state = PhoneApplicationService.Current.State;

        byte[] LastCachedImage = (byte[])state["ImageCache"];

        if (LastCachedImage != null)
        {
            CachedImage.Source = _GetImage(LastCachedImage);
            DownloadImage = false;
        }
    }
    catch { }

    if(DownloadImage == true)
    {
        //Failed to pull image out of state, set to direct URL
        Uri u = new Uri(
            "http://antwrp.gsfc.nasa.gov/apod/image/0806/saturn6_cassini_big.jpg",
            UriKind.Absolute);
        CachedImage.Source = new BitmapImage(u);
    }
}

 

The method _GetImage is the counter to _GetSaveBuffer, it changes a Byte array into a WriteableBitmap.  Now when the page loads it attempts to load the image from the transient application state.  Failing to do that it loads it directly from the URI.  Now when the user goes back to the application on restoring the image is instantly displayed, no downloading is needed.  Because we are storing in transient application state, the cached image is only temporary.  Restarting the application, that is loading from directly from its icon, will start a new session and the transient application state will be erased. 

Other things that could be done with this is to store into persistent data.  This also works when the image object is bound to a datacontext.  We simply override the binding and use the cached data in the same way.

Grab the sample project with this code here.

 
5 Comments

Posted in WP7