Accueil Nos publications Blog Windows Phone 7 – Parlons SplashScreens

Windows Phone 7 – Parlons SplashScreens

A l’origine, un splashscreen est une page, une image, ou encore un formulaire, invitant l’utilisateur à attendre pendant un chargement de données au sein d’une application. Non seulement cela, mais, elle apporte aussi une petite identité visuelle à l’application préparant à son utilisation. Enfin, c’est cette première définition qui pour nous a plus de raison d’être, surtout si votre application consomme des données (ou effectue plusieurs traitements) à son démarrage. Je vous propose dans cet article de découvrir comment exploiter au mieux un splashscreen pour améliorer sensiblement les performances au démarrage de votre application WP7.

1/ Splashscreen fixe et splashscreen utile ? Quel intérêt ?

Comprenons-nous bien, par fixe, je veux dire, simplement une image, et par utile, je veux simplement dire qu’il s’agit d’un splashscreen avec un traitement pouvant être effectué (dynamique) ou pas (statique).
Bien, donc, comme nous le disions précédemment, le splashscreen ne sera utilisé qu’au démarrage de l’application. Si votre application ne fait aucun traitement à son démarrage (aucune préparation de données, aucun téléchargement) et que vous n’avez pas besoin de préchargement, un joli splashscreen statique suffira amplement.

Quand vous créez une application WP7, par défaut, une image SplashScreen est créée. Le temps de chargement de cette image est variable (selon le type du smartphone, ses ressources, son espace disponible, sa mémoire, etc. …). Par ailleurs, une image ne vous permettra jamais d’effectuer un mécanisme d’attente, de chargement de données. Il faut l’implémenter. La durée de votre traitement sera rallongée de la durée d’affichage du splashscreen. C’est ce qui s’est passé pour moi concernant ma dernière application publiée sur le marketplace.

2/ Mettre en place un splashscreen utile

Nous allons tout d’abord créer un contrôle utilisateur que nous appellerons SplashScreenControl.xaml. Pour les puristes du pattern MVVM, cette page peut être une vue (qui pourra avoir donc un ViewModel associé).

Pourquoi créer un contrôle utilisateur et pas une page ?
Cela aurait pu être possible. Cependant, il y aurait eu un inconvénient assez gênant, ce serait le bouton Back du téléphone.
Il faudrait bloquer et empêcher la navigation vers la page de notre SplashScreen depuis la page MainPage.xaml. Dans ce cas, notre application ne pourrait plus passer par l’évènement Application_Closing qui est justement appelé en fin de cycle de navigation (depuis la page Root) de notre application et qui est censé la fermer.

Voici le code xaml le plus simple de ce contrôle



<UserControl x:Class="monsmartphone.Controls.ErrorMessageControl"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    d:DesignHeight="480" d:DesignWidth="480">


<Grid x:Name="LayoutRoot" Width="480" Height="800">
<Grid.Background>
<ImageBrush ImageSource="/Resources/Images/SplashScreenImage.jpg" Stretch="Fill"  />
</Grid.Background>
</Grid>

</UserControl>

Pourquoi mettre l’image en Background ?
Ce n’est pas obligatoire, mais si vous souhaitez par exemple afficher des messages d’information par dessus votre image quant à l’évolution de votre traitement, cela peut être un avantage de procéder ainsi.

Où doit-on effectuer le traitement de préchargement ?
Il n’y a pas vraiment de préférence, et cela peut être fait dans le contrôle utilisateur lui-même (pour éviter de “surcharger” la page principale et en détacher un peu de logique).

Voici le code behind le plus simple de ce contrôle :


using System;
using System.Windows.Controls;
using System.Windows.Threading;

namespace Wp7SplashScreenSample.Controls
{
public partial class SplashScreenControl : UserControl
{
private const int MAX_DURATION = 5; //seconds
private DispatcherTimer _timer;

public SplashScreenControl()
{
InitializeComponent();

_timer = new DispatcherTimer();
this.Loaded += (o, e) =>
{
_timer.Interval = TimeSpan.FromSeconds(MAX_DURATION);
_timer.Tick += new EventHandler(TimerTick);
_timer.Start();
//TODO HERE
};
}

private void TimerTick(object sender, EventArgs e)
{
_timer.Stop();
_timer.Tick -= new EventHandler(TimerTick);
this.Visibility = System.Windows.Visibility.Collapsed;
}
}
}

Le traitement que vous souhaitez effectuer doit se faire tout de suite après le démarrage du Timer.

Pourquoi une durée maximale de 5 secondes ?
C’est une contrainte imposée par Microsoft afin qu’une application puisse être validée sur le marketplace si elle dispose d’un splashscreen. Cette contrainte figure dans le guide de certification des applications (Windows Phone 7 Application Certification Requirements).

Citons :

5.2.1 Launch Time
a. The application must render the first screen within 5 seconds after launch.
The application may provide a splash screen image in a file called SplashScreenImage.jpg in the root of the XAP package while the application is still trying to load. However, the first application screen must be rendered within the 5 second requirement even when there is a splash screen.
Microsoft recommends that the application provides a splash screen image only when it takes longer than 1 second to load the first screen.
b. Within 20 seconds after launch, the application must be responsive to user input.

Que se passe t-il si notre traitement n’est pas fini ?
Dans ce cas, il sera interrompu lorsque le contrôle changera d’état (de Visible à Collapsed). Il faudra dans ce cas recommencer son exécution sur la page principale. Cependant, les flux arrivent généralement à être chargés très rapidement (attention au poids du flux, sa disponibilité, etc. …). Il faudra également avoir une gestion d’erreur à ce niveau.

Pour pouvoir afficher la popup, il faut simplement créer une méthode comme cela :


private void DisplayPopup()
{
Popup splash = new Popup();
splash.Child = new SplashScreenControl();
splash.IsOpen = true;
}

Ensuite, appeler cette méthode tout de suite après le InitializeComponent();


public MainPage()
{
InitializeComponent();
DisplayPopup();
}

Toutefois, notre code présente un mauvais fonctionnement. Si on désactive notre application (Bouton Windows) puis que l’on clique que le bouton Retour (Back), notre SplashScreen sera appelé de nouveau.

Il faut donc penser à gérer son état. Pour cela, on peut utiliser l’IsolatedStorage. Voici le nouveau code de notre méthode DisplayPopup.


private void DisplayPopup()
{
var settings = IsolatedStorageSettings.ApplicationSettings;
bool displayMe = false;

if (!settings.Contains("SplashScreenDisplayed")) {
settings.Add("SplashScreenDisplayed", true);
displayMe = true;
}
else {
displayMe = (bool)settings["SplashScreenDisplayed"];
}

if (displayMe) {
Popup splash = new Popup();
splash.Child = new SplashScreenControl();
splash.IsOpen = true;
}
}

Attention à ne pas oublier de changer la valeur de notre clé quand on désactive ou que l’on quitte notre application dans le fichier App.xaml.cs


// Code to execute when the application is deactivated (sent to background)
// This code will not execute when the application is closing
private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
var settings = IsolatedStorageSettings.ApplicationSettings;
if (settings.Contains("SplashScreenDisplayed")) {
settings["SplashScreenDisplayed"] = false;
}
}

// Code to execute when the application is closing (eg, user hit Back)
// This code will not execute when the application is deactivated
private void Application_Closing(object sender, ClosingEventArgs e)
{
var settings = IsolatedStorageSettings.ApplicationSettings;
if (settings.Contains("SplashScreenDisplayed")) {
settings["SplashScreenDisplayed"] = true;
}
ViewModelLocator.Cleanup();
}

Conclusion

Nous n’en avons pas parlé, mais, les traitements effectués avec le splashscreen ne doivent pas pour autant être synchrones. Ne perdez donc pas cet aspect de vue. Ensuite, cette approche de splashscreen est bien entendu une porte ouverte pour les splashscreens animés si vous êtes motivés. Attention toutefois à ne pas perdre de vue les performances qui peuvent faire en sorte que votre application ne soit pas certifiée. Non seulement les performances, mais aussi la gestion des erreurs qui peuvent découler de ces traitements.
Bon développement et à bientôt!