Сделать сборщик файлов асинхронным - Windows Phone 8.1

1

Я попытался сделать File open picker асинхронным, используя TaskComplectionSource однако иногда я закрываю приложение с возвращаемым значением -1, иногда я получаю исключение, например:

[System.Runtime.InteropServices.COMException] = {System.Runtime.InteropServices.COMException (0x80004005): Unspecified error

Unspecified error

   at Windows.Storage.Pickers.FileOpenPicker.PickSingleFileAndContinue()
   at PhotosGraphos.Mobile.Common.StorageFileExtensions.<PickSingleFileAsyncMobile..

Код:

public static class StorageFileExtensions
{
    private static TaskCompletionSource<StorageFile> PickFileTaskCompletionSource;

    private static bool isPickingFileInProgress;
    public static async Task<StorageFile> PickSingleFileAsyncMobile(this FileOpenPicker openPicker)
    {
        if (isPickingFileInProgress)
            return null;

        isPickingFileInProgress = true;
        PickFileTaskCompletionSource = new TaskCompletionSource<StorageFile>();

        var currentView = CoreApplication.GetCurrentView();
        currentView.Activated += OnActivated;
        openPicker.PickSingleFileAndContinue();

        StorageFile pickedFile;
        try
        {
            pickedFile = await PickFileTaskCompletionSource.Task;
        }
        catch (TaskCanceledException)
        {
            pickedFile = null;
        }
        finally
        {
            PickFileTaskCompletionSource = null;
            isPickingFileInProgress = false;
        }

        return pickedFile;
    }

    private static void OnActivated(CoreApplicationView sender, IActivatedEventArgs args)
    {
        var continuationArgs = args as FileOpenPickerContinuationEventArgs;
        sender.Activated -= OnActivated;

        if (continuationArgs != null && continuationArgs.Files.Any())
        {
            StorageFile pickedFile = continuationArgs.Files.First();
            PickFileTaskCompletionSource.SetResult(pickedFile);
        }
        else
        {
            PickFileTaskCompletionSource.SetCanceled();
        }
    }
}

Что странно - эта ошибка вряд ли воспроизводится во время отладки. Кто-нибудь знает, что может быть причиной этого?

  • 1
    Для начала, вы не должны использовать статический источник завершения задачи для каждого вызова этого метода. Он должен быть локальным для вызова метода.
  • 0
    Вы правы - это явно "кодовый запах". Однако в нем нет ничего плохого, о чем я упомянул в своем вопросе - он не используется нигде вне этого метода, это не многопоточный метод (сборщик не может быть запущен из потока, не являющегося пользовательским интерфейсом), поэтому условия гонки здесь не существуют. ,
Теги:
windows-runtime
windows-phone-8.1

2 ответа

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

Не делайте этого (не пытайтесь включить поведение продолжения в async). Зачем?

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

Также обратите внимание, что когда вы обычно запускаете приложение и запускаете сборщик, тогда в некоторых случаях ваше приложение может быть прекращено (низкие ресурсы, пользователь закрывает его...). Итак, вам нужны две вещи, которые добавляются VS в качестве шаблона: ContinuationManager и SuspensionManager. Больше вы найдете в MSDN. В той же ссылке вы найдете хорошую процедуру для отладки вашего приложения:

Выполните следующие действия, чтобы проверить случай, когда ваше приложение завершается после вызова метода AndContinue. Эти шаги гарантируют, что отладчик снова подключится к вашему приложению после завершения операции и продолжения.

  1. В Visual Studio щелкните правой кнопкой мыши проект и выберите "Свойства".

  2. В Project Designer на вкладке "Отладка" в разделе "Действие" включите "Не запускать", но отлаживайте мой код при его запуске.

  3. Запустите приложение с помощью отладки. Это развертывает приложение, но не запускает его.

  4. Запустите приложение вручную. Отладчик подключается к приложению. Если у вас есть точки останова в коде, отладчик останавливается на контрольных точках. Когда ваше приложение вызывает метод AndContinue, отладчик продолжает работать.

  5. Если ваше приложение вызывает сборщик файлов, подождите, пока вы не откроете поставщика файлов (например, "Телефон", "Фотографии" или "OneDrive"). Если ваше приложение вызывает поставщика онлайн-удостоверения, подождите, пока откроется страница проверки подлинности.

  6. На панели инструментов "Отладка местоположения" в раскрывающемся списке "Процесс" выберите процесс для вашего приложения. В раскрывающемся списке "События жизненного цикла" выберите "Приостановка и завершение работы", чтобы завершить работу приложения, но оставите работу эмулятора.

  7. После завершения операции AndContinue отладчик автоматически присоединяется к вашему приложению, когда приложение будет продолжено.

  • 0
    отличный ответ, хотя уже знал о ContinuationManager, я думал, что это можно упростить. Знаете ли вы, что именно происходит с ожидаемым TaskCompletionSource, когда приложение приостанавливается?
  • 0
    @fex В большинстве случаев ресурсы сохраняются в памяти: операционная система пытается сохранить как можно больше приостановленных приложений в памяти - вы можете прочитать больше на MSDN . Я не уверен, вернется ли программа к точке после ожидающего TCS - конечно, вы можете это проверить - в выпадающем списке «События жизненного цикла» выберите «Приостановить», а затем «Возобновить» - вы можете проверить, что происходит.
1

Я изменил сборщик файлов на стандартный способ, предоставленный @Romasz - он все еще рушился. Я отлаживал его часами, и я получаю COMException же COMException но иногда с предоставленной информацией:

"GetNavigationState doesn't support serialization of a parameter type which was passed to Frame.Navigate"

Кажется, что код с TaskCompletionSource работает, и нет ничего плохого в этом. Я узнал в документации msdn для Frame

Note: The serialization format used by these methods is for internal use only. Your app should not form any dependencies on it. Additionally, this format supports serialization only for basic types like string, char, numeric and GUID types.

И я передавал объект модельного класса в параметр навигации - поэтому он хранился в стеке навигации, поэтому он не мог быть сериализован. Урок: не используйте непримитивные типы для параметра навигации. Frame.Navigate должен запретить такую навигацию и исключение исключения, но это не так.

EDIT: Еще одна ошибка: если вы привязали нажатие (пусть говорят, нажали кнопку) или событие, подобное этому, чтобы запустить запуск FileOpenPicker вам нужно проверить, был ли ранее picker.PickFile.. - иначе, когда вы быстро нажимаете эту кнопку, вы получите несколько вызовов для picker.PickFile.. и UnauthorizedAccessException будут выбрасываться.

  • 1
    +1 - остерегайтесь только случая, когда ваше приложение завершается в фоновом режиме ОС (редкий случай, но может случиться). Также я бы не назвал ошибку двойным касанием , просто замечание, что мы должны убедиться, что пользователь не будет запускать сборщик несколько раз.

Ещё вопросы

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