Windows Phone

3 posts

HTTP and images in Windows Phone

I continue to explore different techniques of displaying images in Windows Phone and this time I will show some possible implementations of fetching them from the web using the HTTP protocol.

Classic implementation:

public static void GethttpImage1(string urlImage, Action<BitmapImage> action)  
{
  var request = (HttpWebRequest)WebRequest.Create(urlImage);
  request.BeginGetResponse(result =>
  {
    using (var sr = request.EndGetResponse(result))
    {
        Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
                var image = new BitmapImage();
                image.SetSource(sr.GetResponseStream());
                if (action != null)
                    action(image);
                sr.Close();
            });
    }
  }
}

urlImage is a string representation of the url of the image : example : http://dev.bratched.fr/download/testimage1.png

This method uses the WebRequest class and reads the response as a Stream using request.EndGetResponse.

The

Deployment.Current.Dispatcher.BeginInvoke(() =>

call is very important as it allows us to use the BitmapImage on the main UI thread even when the callback is invoked on a background thread.

The method will invoke the action and pass the retrieved image to this action as parameter.

It can be invoked like this in order to set a property of type BitmapImage:

HttpImageService.GethttpImage1("http://dev.bratched.fr/download/testimage1.png", b =>
    {
       Image = b;
    });

Implementation with async/await:

The “Microsoft Async” allows to use the async/await pattern in the standard Windows Phone methods.

NuGetPackagesAsync

This package adds some extension methods to the standard WebRequest class returning Task<BitmapImage>

using (WebResponse response = await request.GetResponseAsync())

 

Replaces the following elements:

request.BeginGetResponse(result =>
  {
    using (var sr = request.EndGetResponse(result))
    {

The function returns directly a Task<BitmapImage> instead of passing an action as parameter

public static async Task<BitmapImage> GethttpImage2(string urlImage)
{
    try
    {
        var request = (HttpWebRequest)WebRequest.Create(urlImage);
        using (WebResponse response = await request.GetResponseAsync())
        {
            BitmapImage image = null;
            DispatcherSynchronizationContext dsc = new DispatcherSynchronizationContext(Deployment.Current.Dispatcher);
            await Task.Factory.StartNew(() =>
            {
                dsc.Send(_ =>
                {
                    image = new BitmapImage();
                    image.SetSource(response.GetResponseStream());
                }, null);
            });
            return image;
        }
    }
    catch (Exception)
    {
        return null;
    }
}

Remark :

DispatcherSynchronizationContext dsc = new DispatcherSynchronizationContext(Deployment.Current.Dispatcher);
            await Task.Factory.StartNew(() =>
            {
                dsc.Send(_ =>
                {

replaces

Deployment.Current.Dispatcher.BeginInvoke(() =>

Here we still need to marshal the call on the main Thread to allow using the returned BitmapImage and bind it on the UI.

The async/await pattern illustrated here allows better management of the threads as it relies on the TPL. Vous pouvez la remplacer sans soucis par l’ancien code.

Here’s how you could call the function: (Image is a property of type BitmapImage)

Image = await HttpImageService.GethttpImage2("http://dev.bratched.fr/download/testimage1.png");

HttpClient

The “Microsoft HTTP Client Libraries” NuGet needs to be installed in order to be able to use the HttpClient class. The advantage of this class is that it allows to use the same syntax as we would in a Windows 8 application.

NuGetPackageshttpClient

Important remark: it’s necessary to use a buffer instead of a Stream because

  • BitmapImage needs to be used on the main Thread
  • The Main thread cannot be used in AsyncStream

 

public static async Task<BitmapImage> GethttpImage3(string urlImage)
{
    try
    {

        HttpClient httpClient = new HttpClient() { MaxResponseContentBufferSize = 100000000 };
        var ImageData = await httpClient.GetByteArrayAsync(urlImage);
        {
            using (var s = new MemoryStream(ImageData))
            {
                BitmapImage image = null;
                DispatcherSynchronizationContext dsc = new DispatcherSynchronizationContext(Deployment.Current.Dispatcher);
                await Task.Factory.StartNew(() =>
                {
                    dsc.Send(_ =>
                    {
                        image = new BitmapImage();
                        image.SetSource(s);
                    }, null);
                });
                return image;
            }
        }
    }
    catch
    {
        return null;
    }
}

This function can be called the same way as before:

Image = await HttpImageService.GethttpImage3("http://dev.bratched.fr/download/testimage1.png");

Performance tests

The 3 methods can be used but which one performs better when loading multiple images?

I have adapted the previous program from Performance tests of static images to

  • Display the 3 methods in the lists
  • Benchmark by loading 10 times the big png image (400K 1000×1000) from the previous article

I have also added the MemoryCounter from Coding4Fun to follow the memory usage.

Here are the results from a WiFi network (average from 20 passes).

  • Method 1 : HttpRequest/Response with Action callback : 6 sec
  • Method 2 : Async HttpRequest/Response : 9 sec
  • Method 3 : HttpClient : 8,5 sec

 

During the tests I have also inverted the order of passes to avoid influencing the results.

La consultation des listes donne un réel aperçu des 3 différentes méthodes.

C’est encore une fois la méthode “classique” avec HttpRequest qui donne le meilleur résultat.

Le système d’Action permet d’éviter l’attente de la fin du traitement du thread pour interroger le réseau et permet ainsi une meilleure parallélisassions des tâches.

Sharing of source code in Windows and Windows Phone projects

The Portable Class Library (PCL)

The portable Class library (PCL) will allow us to share a large part of the code across projects.

It is possible for a few years to share the PCL code between projects (Sliverlight and WPF, Windows Phone, Windows 8,…).
More projects are different, the more shared classes decreases.

It is important to see that this Library can be used for projects compatible with the selected options.

Note also the visual studio Express editions do not create a PCL, but instead accepts their use in a project.

This Library may use a library which would not have at least the same options selected.

PCL_WindowsMenu

Continue reading

Visual Studio versions for your Windows Phone Apps?

Windows Phone 7.x, 8.0 and 8.1

3 major versions of Windows Phone exist since April: 7.x, 8 and 8.1.

The 8.1 version allows among others to create ‘classic’ Windows Phone 8.1 applications called 8.1 – Silverlight (SL) and also Universal applications that can be shared between Windows 8.1 and Windows Phone 8.1.

Having common codebase was already partially possible with the PCL (Portable Class Libraries). The compiled assembly can be used in Windows Phone 7.x, WP8 and Windows 8 project for example.

With Universals Apps the UI code can also be shared.

Visual Studio 2013 allows for creating PCL compatible with WP8, W8, WP8.1, W8.1 which can be used in classic Windows Phone applications and Windows 8.x with Universal Apps projects.

But Visual Studio 2013 is no longer compatible with WP7.x.

Windows Phone 7.x still represents 19% of Windows Phone users in April 2014 (click on the image for the full survey of adduplex).

clip_image003_thumb

So you need to make a choice.

If you want to create an application for Windows Phone 7.x you need to use Visual Studio 2012. The PCL will be compatible WP7 and WP8, as well as the Windows Phone 7.x application.

Summary

The diagram below shows the possibilities of each Visual Studio version.

Depending on how the PCLwas built, your code may or may not be shared between a Windows Phone 7 project and a Windows Phone 8.1 project.

Continue reading