Развертывание асинхронной операции и ее асинхронного обратного вызова в TaskCompletionSource

У меня есть метод в сервисе, который вызывается моей моделью представления для получения изображения. Изображение извлекается из внешней библиотеки (iOS API в Xamarin), которая использует механизм обратного вызова вместо ожидания.

Чтобы сделать мой метод приемлемым, я обертываю метод в TaskCompletionSource. Хотя проблема в обратном вызове API, мне нужно вызвать другой метод, который должен вернуть задачу. Источник завершения устанавливает его результат как Task<IBitmap>, а затем я возвращаю задачу CompletionSource, которая теперь становится Task<Task<IBitmap>> Итак, что я получаю в качестве окончательного значения возврата Task<Task<IBitmap>> вместо просто Task<Bitmap>,

public Task<IBitmap> GetAlbumCoverImage(IAlbum album)
{
    var assets = PHAsset.FetchAssetsUsingLocalIdentifiers(new string[] { album.Identifier }, null);

    var asset = assets.FirstOrDefault(item => item is PHAsset);
    if(asset == null)
    {
        return null;
    }

    var taskCompletionSource = new TaskCompletionSource<Task<IBitmap>>();
    PHImageManager.DefaultManager.RequestImageForAsset(
        asset, 
        new CoreGraphics.CGSize(512, 512), 
        PHImageContentMode.AspectFit, 
        null, 
        (image, info) => taskCompletionSource.SetResult(this.ConvertUIImageToBitmap(image)));

    return taskCompletionSource.Task;
}

private Task<IBitmap> ConvertUIImageToBitmap(UIImage image)
{
    var imageData = image.AsJPEG().GetBase64EncodedData(Foundation.NSDataBase64EncodingOptions.SixtyFourCharacterLineLength);
    byte[] imageBytes = new byte[imageData.Count()];

    System.Runtime.InteropServices.Marshal.Copy(imageData.Bytes, imageBytes, 0, Convert.ToInt32(imageData.Count()));

    return BitmapLoader.Current.Load(new MemoryStream(imageBytes), 512, 512);
}

Как мне развернуть вложенную задачу, чтобы я только возвращал Task<IBitmap>?

1 ответ

Решение

Вам не нужно использовать TaskCompletionSource<Task<IBitmap>>использовать TaskCompletionSource<UIImage> которая возвращает задачу, которая после завершения возвращает изображение. Ожидайте эту задачу, чтобы асинхронно получить результат, который затем можно преобразовать, используя ConvertUIImageToBitmap:

public async Task<IBitmap> GetAlbumCoverImage(IAlbum album)
{
    // ...
    var taskCompletionSource = new TaskCompletionSource<UIImage>(); // create the completion source
    PHImageManager.DefaultManager.RequestImageForAsset(
        asset, 
        new CoreGraphics.CGSize(512, 512), 
        PHImageContentMode.AspectFit, 
        null, 
        (image, info) => taskCompletionSource.SetResult(image)); // set its result

    UIImage image = await taskCompletionSource.Task; // asynchronously wait for the result
    return await ConvertUIImageToBitmap(image); // convert it
}
Другие вопросы по тегам