Зависание при попытке прочитать файл с помощью PCLStorage

1

Я использую библиотеку PCLStorage в своем проекте, чтобы получить доступ к файловой системе из моего PCL lib. Я пытаюсь прочитать файл следующим образом:

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);
    }

Поскольку PCLStorage является асинхронным, и я хочу использовать его в синхронном коде, я вызываю его следующим образом:

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

Проблема в том, что все приложение зависает, когда я пытаюсь выполнить этот код. Как описано выше в комментариях, код в методе LoadAsync не выполняется. Я использую новейший Xamarin 3. Моя библиотека PCL упоминается в проекте Xamarin iOS. Оба проекта имеют ссылки на PCLStorage через самородок.

С другой стороны, следующий код выполняется правильно:

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 ());
    }
Теги:
xamarin
portable-class-library

1 ответ

4
Лучший ответ

Это всегда потенциальный рецепт катастрофы:

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

Если это происходит в потоке пользовательского интерфейса, то вы фактически блокируете поток пользовательского интерфейса до завершения задачи, но задача также должна будет выполнять его продолжения в потоке пользовательского интерфейса. У тебя тупик.

В основном вы должны пытаться структурировать свое приложение, чтобы больше охватывать асинхронность. Вы можете использовать Task.ConfigureAwait() для планирования продолжений в LoadAsync для выполнения в LoadAsync потоков потоков вместо этого, но вы по-прежнему будете блокировать пользовательский интерфейс до его завершения, что противоречит духу асинхронности.

Асинхронность несколько вирусная - если вы попытаетесь сделать только одну часть вашего асинхронного приложения, вам будет трудно. Вы должны быть асинхронными вплоть до, по крайней мере, с точки зрения операций пользовательского интерфейса.

(Если вы заблокируете ожидание задачи, возвращенной PersistAsync вас будет аналогичная проблема, кстати.)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню