Question

J'utilise la bibliothèque PCLStorage dans mon projet afin de pouvoir accéder au système de fichiers depuis ma bibliothèque PCL.J'essaie de lire un fichier comme suit :

static async Task<T> LoadAsync<T> (string fileName) where T : class
    {
        var rootFolder = FileSystem.Current.LocalStorage; // debugger stops here
        var m5cacheFolder = await rootFolder.GetFolderAsync (CacheFolderName); // but instead of going to this line, jumps to end of this method
        var userInfoFile = await m5cacheFolder.GetFileAsync (fileName);
        var userInfoFileContent = await userInfoFile.ReadAllTextAsync ();
        var stringReader = new StringReader (userInfoFileContent);
        var serializer = new XmlSerializer (typeof(T));
        return (T)serializer.Deserialize (stringReader);
    }

Puisque PCLStorage est asynchrone et que je souhaite l'utiliser dans un code synchrone, je l'appelle comme ceci :

var task = LoadAsync<User> (UserInfoFileName);
user = task.Result;

Le problème est que toute l'application se bloque lorsque j'essaie d'exécuter ce code.Comme décrit dans les commentaires ci-dessus, le code de la méthode LoadAsync n'est pas exécuté.J'utilise le dernier Xamarin 3.Ma bibliothèque PCL est référencée dans le projet Xamarin iOS.Les deux projets font référence à PCLStorage via nugget.

Par contre le code suivant est exécuté correctement :

static async void PersistAsync (object obj, string fileName)
    {
        var rootFolder = FileSystem.Current.LocalStorage;
        var m5cacheFolder = await rootFolder.CreateFolderAsync (CacheFolderName, CreationCollisionOption.OpenIfExists);
        var userInfoFile = await m5cacheFolder.CreateFileAsync (fileName, CreationCollisionOption.ReplaceExisting);
        var serializer = new XmlSerializer (obj.GetType ());
        var stringWriter = new StringWriter ();
        serializer.Serialize (stringWriter, obj);
        await userInfoFile.WriteAllTextAsync (stringWriter.ToString ());
    }
Était-ce utile?

La solution

C’est toujours une recette potentielle pour un désastre :

var task = LoadAsync<User>(UserInfoFileName);
user = task.Result;

Si cela se produit dans le thread de l'interface utilisateur, vous bloquez essentiellement le thread de l'interface utilisateur jusqu'à ce que la tâche soit terminée - mais la tâche devra également exécuter ses continuations sur le thread de l'interface utilisateur.Vous êtes dans une impasse.

Fondamentalement, vous devriez essayer de structurer votre application pour adopter davantage l'asynchronie.Toi pourrait utiliser Task.ConfigureAwait() pour programmer les suites dans LoadAsync pour exécuter sur les threads du pool de threads à la place, mais vous allez toujours bloquer l'interface utilisateur jusqu'à ce qu'elle soit terminée, ce qui est contraire à l'esprit de l'asynchronie.

L'asynchronie est quelque peu virale - si vous essayez de créer simplement un une partie de votre application asynchrone, vous allez avoir du mal.Vous devez être asynchrone jusqu'au bout, au moins en termes d'opérations d'interface utilisateur.

(Si vous bloquez l'attente de la tâche renvoyée par PersistAsync d'ailleurs, vous aurez un problème similaire.)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top