展开异步操作及其在 TaskCompletionSource 中的异步回调
Unwrapping an async operation and it's async callback in a TaskCompletionSource
我的视图模型调用服务中的一个方法来获取图像。该图像是从外部库(Xamarin 中的iOS API)获取的,它使用回调机制而不是可等待的。
为了让我的方法可以等待,我将方法包装在 TaskCompletionSource 中。虽然问题出在 API 回调中,但我需要调用另一个必须 return 任务的方法。完成源将其结果设置为 Task<IBitmap>
,然后我 return CompletionSource 任务,现在变成 Task<Task<IBitmap>>
所以我最终得到的 return 值是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);
}
我应该如何展开嵌套任务,以便我只 returning Task<IBitmap>
?
您不需要使用 TaskCompletionSource<Task<IBitmap>>
,使用 TaskCompletionSource<UIImage>
其中 returns 一个任务,完成后 returns 一个图像。等待该任务异步获取结果,然后您可以使用 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
}
我的视图模型调用服务中的一个方法来获取图像。该图像是从外部库(Xamarin 中的iOS API)获取的,它使用回调机制而不是可等待的。
为了让我的方法可以等待,我将方法包装在 TaskCompletionSource 中。虽然问题出在 API 回调中,但我需要调用另一个必须 return 任务的方法。完成源将其结果设置为 Task<IBitmap>
,然后我 return CompletionSource 任务,现在变成 Task<Task<IBitmap>>
所以我最终得到的 return 值是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);
}
我应该如何展开嵌套任务,以便我只 returning Task<IBitmap>
?
您不需要使用 TaskCompletionSource<Task<IBitmap>>
,使用 TaskCompletionSource<UIImage>
其中 returns 一个任务,完成后 returns 一个图像。等待该任务异步获取结果,然后您可以使用 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
}