12/08/2013

[WindowsPhone] Lecteur de flux : LiveTiles, Isolated Storage & BackgroundAgent

Bonjour à toutes et à tous,
nous nous retrouvons pour la cinquième et dernière partie sur le lecteur de flux RSS, ou nous verrons comment mettre en place des LiveTiles et les mettre à jour via un BackgroundAgent. C'est parti !.

Dossier complet

  1. [WindowsPhone] Lecteur de flux : Couche Model
  2. [WindowsPhone] Lecteur de flux : Couche ViewModel
  3. [WindowsPhone] Lecteur de flux : Couche View
  4. [WindowsPhone] Lecteur de flux : Le détail du post
  5. [WindowsPhone] Lecteur de flux : LiveTiles, Isolated Storage & BackgroundAgent

LiveTiles

Il existe trois types de tuiles dynamiques :

  • Flip
  • Iconic
  • Cycle
Pour plus d'infos, ou pour avoir un visuel de ces différents types tuiles c'est par ici.

Dans notre application, nous allons choisir d'utiliser les Flip.
Et nous allons choisir de réinitialiser notre Tile à chaque fois que l'application va se lancer. Du coup dans notre fichier MainPage.xaml.cs, nous codons une méthode ResetLiveTilte:

using Microsoft.Phone.Shell;
// ...
        private void ResetLiveTile()
        {
            FlipTileData primaryTileData = new FlipTileData();
            primaryTileData.Count = 0;
            primaryTileData.Title = AppResources.LiveTilesTitle;
            primaryTileData.BackContent = "";
            ShellTile primaryTile = ShellTile.ActiveTiles.First();
            primaryTile.Update(primaryTileData);
        }

Nous créons des données de FlipTile que nous réinitialisons. On passe le BackContent à "" pour arrêter l'effet de rotation. Ensuite nous récupérons la première ShellTile active et nous la mettons à jour avec les données du FlipTileData.

Isolated Storage

Maintenant nous devons vérifier si de nouveaux articles ont été écrits depuis la dernière dernière fois que l'application a été ouverte. Nous allons donc retourner dans notre PostViewModel et nous allons créer une méthode qui va nous permettre de garder la dernière synchronisation qu'aura effectué l'utilisateur et qui servira de référence à notre tâche périodique.

        void UpdateIsoStorage()
        {
            var myDate = Convert.ToDateTime(DateTime.Now, CultureInfo.InvariantCulture);
            IsolatedStorageFile myIsoStorage = IsolatedStorageFile.GetUserStoreForApplication();

            StreamWriter myStream = new StreamWriter(new IsolatedStorageFileStream("LastUpdate.txt", FileMode.Create, FileAccess.Write, myIsoStorage));
            myStream.Write(myDate);
            myStream.Close();
        }

Nous récupérons l'Isolated Storage dédié à notre application sur le téléphone de l'utilisateur et nous écrivons la valeur dans un fichier LastUpdate.txt. Bien penser à fermer le flux. Et nous allons lever cette méthode lorsque le chargement asynchrone sera terminé :

            Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
                MyBlogPosts = BloggerSvc.PostData;
                IsBusy = false;
                OnTreatmentComplete();
            });
            UpdateIsoStorage();

Maintenant on peut s'occuper de la tâche périodique.

BackgroundAgent

Donc nous insérons un nouveau projet de type Windows Phone Scheduled Task Agent. Dans notre fichier ScheduleAgent.cs nous le transformons comme ceci :

        public static void LaunchForTest(string name, TimeSpan delay)
        {

        }
        protected override void OnInvoke(ScheduledTask task)
        {
            WebClient webClient = new WebClient();
            webClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(webClient_DownloadStringCompleted);
            webClient.DownloadStringAsync(new Uri("http://pascalpereznet.blogspot.com/feeds/posts/default?alt=rss&redirect=false&max-results=30")); 
        }

        void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                
            }
            else
            {
                int myReturnValue = GetNewPostsQuantity(e.Result);
                if (myReturnValue > 0)
                {
                    string myText;
                    if (myReturnValue > 1)
                    {
                        myText = myReturnValue + " nouvel article";
                    }
                    else
                    {
                        myText = myReturnValue + " nouveaux articles";
                    }
                    
                    FlipTileData primaryTileData = new FlipTileData();
                    primaryTileData.Count = myReturnValue;
                    primaryTileData.BackContent = myText;

                    ShellTile primaryTile = ShellTile.ActiveTiles.First();
                    primaryTile.Update(primaryTileData);
                }
                else
                {
                    FlipTileData primaryTileData = new FlipTileData();
                    primaryTileData.Count = 0;
                    primaryTileData.Title = "pascalpereznet";
                    primaryTileData.BackContent = "";
                    ShellTile primaryTile = ShellTile.ActiveTiles.First();
                    primaryTile.Update(primaryTileData);
                }
            }
            NotifyComplete();
        }

        private static int GetNewPostsQuantity(string feedXML)
        {
            try
            {
                var date = String.Empty;
                var flow = XDocument.Parse(feedXML);
                var syncitems = (from si in flow.Descendants("item")
                                 select si.Element("pubDate").Value).ToList();


                using (IsolatedStorageFile myIsoStorage = IsolatedStorageFile.GetUserStoreForApplication())
                {
                    using (IsolatedStorageFileStream myStream = myIsoStorage.OpenFile("LastUpdate.txt", FileMode.Open, FileAccess.Read))
                    {
                        using (StreamReader sr = new StreamReader(myStream))
                        {
                            date = sr.ReadLine();
                        }
                    }

                }
                DateTime MyDate = new DateTime();
                if (date != null)
                {
                    MyDate = Convert.ToDateTime(date);
                }
                else
                {
                    MyDate = DateTime.Now;
                }

                int Counter = 0;

                foreach (var item in syncitems)
                {
                    var mycompared = Convert.ToDateTime(item, CultureInfo.InvariantCulture);
                    if (mycompared > MyDate)
                    {
                        Counter++;
                    }
                }

                return Counter;
            }
            catch (Exception)
            {
                return 0;
            }

        }

Nous lançons une recherche asynchrone de l'ensemble des posts. Nous allons ensuite lire la valeur que nous avons stocké dans notre Isolated Storage et compter le nombre d'articles plus récents. En fonction du résultat nous mettons à jour notre liveTile.

Création de notre tâche périodique

Nous allons ensuite rechercher dans le service gérant les tâches planifiées (tâche périodique et tâche intensive) si notre tâche n'existe pas déjà et nous le supprimons. Nous en créons une nouvelle et nous l'ajoutons, C'est lors de l'ajout que nous serons si l'utilisateur a bloqué ou pas les tâches périodiques pour notre application.

        PeriodicTask periodicTask;
        string periodicTaskName = "PeriodicAgent";
        public bool agentsAreEnabled = true;


        private void StartPeriodicAgent()
        {
            agentsAreEnabled = true;
            periodicTask = ScheduledActionService.Find(periodicTaskName) as PeriodicTask;

            if (periodicTask != null)
            {
                try
                {
                    ScheduledActionService.Remove(periodicTaskName);
                }
                catch (Exception)
                {
                }

            }

            periodicTask = new PeriodicTask(periodicTaskName);
            periodicTask.Description = "Check for Updates";

            try
            {
                ScheduledActionService.Add(periodicTask);
#if DEBUG
                ScheduledActionService.LaunchForTest(periodicTaskName, new TimeSpan(0, 0, 10));
#endif
            }
            catch (InvalidOperationException exception)
            {
                if (exception.Message.Contains("BNS Error: The action is disabled"))
                {
                    agentsAreEnabled = false;
                }
                if (exception.Message.Contains("BNS Error: The maximum number of ScheduledActions of this type have already been added."))
                {

                }

            }
            catch (SchedulerServiceException)
            {

            }
        }

le if #DEBUG va nous permettre de lancer rapidement la tâche lors en phase de test pour ne pas attendre que le tâche s'exécute au bout de 30 min.

Conclusion

Voilà, ainsi s'achève mon dossier Windows Phone de cet été.
Vous pouvez retrouver les sources ici
A vendredi pour un nouvel article.

Aucun commentaire:

Enregistrer un commentaire