在TaskCompletionSource中展开一个async操作及其async回调

本文关键字:async 一个 操作 回调 TaskCompletionSource | 更新日期: 2023-09-27 18:18:20

我在一个服务中有一个方法,它被我的视图模型调用来获取图像。图像是从外部库(Xamarin中的iOS API)获取的,该库使用回调机制而不是等待。

为了使我的方法可等待,我将方法包装在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> ?

在TaskCompletionSource中展开一个async操作及其async回调

您不需要使用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
}