2

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

Чтобы сделать мой метод ожидаемым, я переношу этот метод в источник TaskCompletion. Проблема, хотя и в обратном вызове 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>?

ответ

3

Вам не нужно использовать 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 
} 
+0

Это работало большое, спасибо. Поскольку 'ConvertUIImageToBitmap' требует UIImage, мне пришлось изменить источник завершения на' TaskCompletionSource '. Затем я смог вытащить UIImage из ожидаемого результата завершения задачи и передать его в метод ConvertUIImageToBitmap и ждать/возвращать результат. –

+0

'ConvertUIImageToBitmap' действительно должен вернуть задачу. Метод «BitmapLoader.Current.Load» возвращает задачу

+0

@ JohnathonSullinger Да, я пропустил часть 'UIImage', но это идея. – i3arnon