Dot.Blog

C#, XAML, Xamarin, UWP/Android/iOS

Windows.Storage pour Windows Phone 8 et Windows 8

[new:10/10/2013]La programmation sous Windows Phone 8 offre l’avantage d’une plateforme unifiée, comment en tirer partie par exemple en matière de stockage local de données. C’est ce que je vous propose de voir…

Le stockage local de données

En programmation Win32/64 le stockage de données locales est excessivement simple : vous écrivez ce que voulez à l’endroit que vous voulez…

Il est sûr que cette liberté et cette apparente simplicité ont ouvert en grand la porte à tous les abus et à ce qu’il faut bien appeler un gigantesque “bordel”. Les applications en “mettent” partout, l’utilisateur ne sait jamais, sauf sauvegarde totale de ses disques, s’il ne lui en manque pas un bout lorsqu’il souhaite copier ses données sur une autre machine, la désinstallation des applications n’entraine pas toujours le ménage des données qui vont avec ce qui pollue à la longue les disques durs, en cas de bug ou de mauvaise saisie de l’utilisateur on ne sait plus où se trouve le fichier enregistré, etc…

WinRT, tout comme le faisait déjà Silverlight, propose un cadre beaucoup plus rigide. Avec la notion d’Isolated Storage (stockage isolé) il n’est plus question d’en “coller partout”, chaque application se voit restreinte à une zone privée. Cette organisation est forcément plus saine.

Windows Phone 8 et WinRT, un noyau commun

Windows Phone 8 a pour grand avantage de reprendre un noyau WinRT commun avec Windows 8 cela veut dire que des parties importantes de code peuvent désormais être partagées entre une application pour tablette Surface, une version desktop sous Windows 8 et une adaptation pour smartphone.

Si WP8 a créé une rupture de compatibilité avec WP7 paradoxalement cette cassure est moins nette au niveau programmation puisque les applications WP7, en Silverlight, sont supportées par WP8. L’incompatibilité existe entre l’OS et le hardware et beaucoup moins au niveau logiciel.

Deux approches pour les données locales

De cet héritage de WP7, WP8 permet souvent d’utiliser des stratégies différentes pour le même résultat, une qui reste compatible avec WP7, l’autre utilisant les nouvelles API WinRT.

C’est le cas notamment pour l’accès aux données locales.

Quel intérêt pratique ?

Dans l’absolu aucun et nul n’est besoin de reprogrammé ce qui marche déjà en WP7. En revanche c’est pour la création de nouvelles applications qu’il faut se poser la question de la compatibilité du code, soit avec les machines WP7 encore en circulation, soit avec WP8 et donc avec WinRT ce qui permet de partager le même code avec une version pour Surface ou PC.

Ces deux approches peuvent se voir dans le code d’accès à l’espace de stockage de l’application. Soit on y accède via l’Isolated Storage dans un esprit purement Silverlight, soit on utilise les API de l’espace de noms Windows.Storage.

Pour illustrer ces deux façons de faire, nous pouvons regarder le code qui suit.

Exemple

Imaginons le besoin de stocker en local des listes d’objets. L’approche générique sera vraisemblablement la meilleure ainsi que la création d’une méthode statique dans une classe de type helper ou bien sous la forme d’un service (approche plus MVVM qu’on retrouve dans MvvmCross par exemple). Il en ira de même pour la lecture de ces listes d’objets.

Dans ce dernier cas on implémentera une méthode qui s’appellera “LoadList” (nom arbitraire qui a l’avantage d’être clair quant aux intentions de la méthode) et qui retournera une liste générique donc un List<T> ou parfois mieux selon le contexte, un IList<T>.

La méthode acceptera en paramètre le nom du sous-répertoire de stockage et le nom du fichier contenant la liste d’objets.

On limitera les objets aux instances de classes (les structures étant exclues donc).

La première version de ce code donnera dans la première approche (compatibilité WP7) quelque chose comme :

 public static IList<T> LoadList<T>(string folder, string fileName) where T : class
{
    var result = new List<T>();
    var isoStore = IsolatedStorageFile.GetUserStoreForApplication();
     if (!isoStore.DirectoryExists(folder))
                isoStore.CreateDirectory(folder);
 
     var fileStream = string.Format("{0}\\{1}.dat", folder, fileName);
 
      using (var stream = new 
IsolatedStorageFileStream(fileStream, FileMode.OpenOrCreate, isoStore))
      {
          if (stream.Length > 0)
         {
              var dcs = new DataContractSerializer(typeof(List<T>));
               result = dcs.ReadObject(stream) as List<T>;
          }
       }
       return result;
 }

 

Pour l’accès à l’Isolated Storage on pourra aussi s’aider d’une classe helper. Un exemple d’une telle classe se trouve ici : https://github.com/eTilbudsavis/native-windows-phone-sdk/blob/master/Esmann.WP.Common/IsolatedStorage/IsoStorageHelper.cs

On peut aussi choisir d’implémenter la méthode dans un style beaucoup plus moderne, donc en asynchrone, et suivant l’API WinRT. Dans ce cas le même code ressemblera au suivant (qui, on le remarquera ne simplifie rien ce qui est dommage) :

public static async Task<IList<T>> LoadList<T>(string folder, string fileName) where T : class
{
    var applicationFolder = ApplicationData.Current.LocalFolder;
 
    if (!await applicationFolder.FolderExistsAsync(folder))
        applicationFolder.CreateFolderAsync(folder);
 
    var result = new List<T>();
 
    var fileStream = string.Format("{0}\\{1}.dat", folder, fileName);
 
    if (await applicationFolder.FileExistsAsync( fileStream))
    {
        var storageFile = await applicationFolder.GetFileAsync(fileStream);
        using (var inStream = await storageFile.OpenSequentialReadAsync())
        {
            var serializer = new DataContractSerializer(typeof(List<T>));
            result = (List<T>)serializer.ReadObject(inStream.AsStreamForRead());
        }
    }
    return result;
}

 

Conclusion

Il faut faire le bon choix entre toutes ces méthodes qui parfois se superposent, soit dans un style purement Silverlight, soit dans un style purement WinRT.

Le choix de la stratégie dépend grandement du contexte, forcément. Par exemple en cross-plateforme avec MvvmCross on aura intérêt bien entendu à choisir une approche "portable” alors que si on développe une application uniquement pour WP8 et Surface le choix de l’API WinRT sera certainement judicieux.

Mais est-ce judicieux de bloquer son code sur un OS au lieu d’utiliser l’approche cross-plateforme largement présentée cet été dans Dot.Blog, voici une excellente question à se poser !

Stay Tuned !

blog comments powered by Disqus