进度和取消

之前展示的是调用一个异步winrt api的常见场景,但之前的代码忽略了取消和进度更新。为了合理地处理取消和进度更新,就不显式让编译器调用Getawaiter 扩展方法了,而是用WindowsruntimeSystemextensions 类提供的AsTask扩展方法


namespace System {
public static class WindowsRuntimeSystemExtensions {
public static Task AsTask<TProgress>(this IAsyncActionWithProgress<TProgress> source,
CancellationToken cancellationToken, IProgress<TProgress> progress);
public static Task<TResult> AsTask<TResult, TProgress>(
this IAsyncOperationWithProgress<TResult, TProgress> source,
CancellationToken cancellationToken, IProgress<TProgress> progress);
// Simpler overloads not shown here
}
}


这样就可以加入取消和进度了,这是调用异步winrt api的代码:

using System; // For WindowsRuntimeSystemExtensions's AsTask
using System.Threading; // For CancellationTokenSource
internal sealed class MyClass {
private CancellationTokenSource m_cts = new CancellationTokenSource();
// NOTE: If invoked by a GUI thread, all code executes via that GUI thread:
private async void MappingWinRTAsyncToDotNet(WinRType someWinRTObj) {
try {
// Assume XxxAsync returns IAsyncOperationWithProgress<IBuffer, UInt32>
IBuffer result = await someWinRTObj.XxxAsync(...)
.AsTask(m_cts.Token, new Progress<UInt32>(ProgressReport));
// TODO: Completed code
}
catch (TaskCanceledException) { // Derived from OperationCanceledException
// TODO: Cancel code
}
catch (SomeOtherException) {
// TODO: Error code
}
}
private void ProgressReport(UInt32 progress) {
// Update progress code
}
public void Cancel() { m_cts.Cancel(); } // Called sometime later to cancel


这里有两个点值得一提。1,如果你不注意哪一个线程在await之后招行,你可能需要通过调用task的Configure- await方法改进程序的性能,传一个false给continueOnCapturedContext参数。2,这里有一些场景你可能想调用一个异步方法然后阻塞进程直接到操作完成。这些场景包括在构造函数中调用异步方法,比如:你有时候需要调用一个回调中的异步方法,一个重载了虚函数的方法。如果你将方法标记成async,调用你的方法的代码可能在异步方法完成前继续执行,而这通常是不想要的结果。另外,如果方法的返回类型是task或task<tresult>或void,你可以用async标记一个方法,因为很多delegate,virtual,interface方法的签名都没有这些类型,如果你的方法实现调用了一个异步方法,你必须阻塞线程。

下面的例子较好地调用了winrt的异步方法并阻塞了线程,直到操作完成:


StorageFile file = KnownFolders.MusicLibrary.GetFileAsync("Song.mp3").AsTask().GetAwaiter().GetResult();


AsTask方法将返回的对象转换成了.NET的task或task<tresult>对象。然后Getawaiter 方法返回了一个taskawaiter 对象知道如何等待操作完成。它的Getresult 方法阻塞了调用线程直到操作完成,而后要么返回对象要么抛出异常。

虽然你可以这样写代码,但是你不应该写成这样:

StorageFile file = KnownFolders.MusicLibrary.GetFileAsync("Song.mp3").AsTask().Result;

原因是如果查询task的result属性操作失败不会抛出正确的异常而抛出aggregateexception异常。要知道通过getawaiter().getresult()阻塞一个GUI线程可能造成潜在的死锁,强制用户或操作系统终止app,所以你应该尽可能地避免阻塞一个导致异步操作的线程


你可以使用Java中的URLConnection类或者Apache HttpClient库来下载远程文件。为了支持取消下载,你可以在下载过程中使用多线程或者异步任务,并且在用户请求取消时停止下载线程或者任务。 为了计算下载进度,你可以使用URLConnection类的getContentLength()方法获取文件大小,并且在下载过程中通过已经下载的字节数与文件总大小的比例来计算下载进度,然后通过UI组件显示给用户。 以下是一个简单的使用URLConnection类下载远程文件并且支持取消和计算进度的示例代码: ```java import java.io.*; import java.net.URL; import java.net.URLConnection; public class Downloader { private volatile boolean isCancelled; private ProgressListener listener; public Downloader(ProgressListener listener) { this.listener = listener; } public void download(String urlString, String destination) throws IOException { URL url = new URL(urlString); URLConnection connection = url.openConnection(); int fileSize = connection.getContentLength(); int bytesRead = 0; byte[] buffer = new byte[1024]; InputStream input = connection.getInputStream(); OutputStream output = new FileOutputStream(destination); while (!isCancelled) { int count = input.read(buffer); if (count == -1) { break; } output.write(buffer, 0, count); bytesRead += count; listener.onProgress((double) bytesRead / fileSize); } output.close(); input.close(); } public void cancel() { isCancelled = true; } public interface ProgressListener { void onProgress(double progress); } } ``` 你可以通过实现ProgressListener接口来获取下载进度,通过调用Downloader的cancel()方法来取消下载。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值