思路清晰后仅仅只需百来行代码便可轻松编写出一套完整的资源动态下载组件- SerialDownloader和ParallelDownloader,它们共用一个完成资源表,且串行下载集成了优先机制(DownloadPriority),并行下载也根据需要封装了并行队列模式(QueueParallelDownloader):

DownloadBase 

    /// <summary>
/// 下载器基类
/// </summary>
public class DownloadBase { protected readonly static List<string> loadedUri = new List<string>(); /// <summary>
/// 获取已下载完成的地址
/// </summary>
public static List<string> LoadedUri { get { return loadedUri; } } /// <summary>
/// 下载失败(错误)次数
/// </summary>
public static int Error { get; protected set; } }
ParallelDownloader 

   /// <summary>
/// 并行资源下载器
/// </summary>
public sealed class ParallelDownloader : DownloadBase { /// <summary>
/// 资源下载进度中触发
/// </summary>
public event DownloadProgressChangedEventHandler DownloadProgressChanged; /// <summary>
/// 资源下载完成
/// </summary>
public event OpenReadCompletedEventHandler OpenReadCompleted; /// <summary>
/// 当前进度百分比
/// </summary>
public static int ProgressPercentage { get; private set; } readonly static List<string> loadingUri = new List<string>();
readonly static List<string> waitingUri = new List<string>();
/// <summary>
/// 获取当前正在下载的地址
/// </summary>
public static List<string> LoadingUri { get { return loadingUri; } }
/// <summary>
/// 获取等待下载地址队列
/// </summary>
public static List<string> WaitingUri { get { return waitingUri; } } /// <summary>
/// 下载资源文件
/// </summary>
/// <param name="uri">资源相对地址<</param>
/// <param name="userToken">资源参数</param>
/// <param name="waitingTime">如果正在被下载,等待检测时间(单位:毫秒)</param>
public void OpenReadAsync(string uri, object userToken, bool isWaiting, int waitingTime) {
if (loadedUri.Contains(uri)) {
Download(uri, userToken);
} else {
if (loadingUri.Contains(uri)) {
//假如该资源正被下载中,则需要等待,每隔1秒检测一次是否已下载完成
if (isWaiting) {
DispatcherTimer timer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(waitingTime) };
EventHandler handler = null;
timer.Tick += handler = (s, e) => {
if (loadedUri.Contains(uri)) {
timer.Stop();
timer.Tick -= handler;
Download(uri, userToken);
}
};
timer.Start();
}
} else {
if (!waitingUri.Contains(uri)) { waitingUri.Add(uri); }
loadingUri.Add(uri);
Download(uri, userToken);
}
}
} /// <summary>
/// 开始下载
/// </summary>
/// <param name="uri">资源相对地址</param>
/// <param name="userToken">资源参数</param>
void Download(string uri, object userToken) {
OpenReadCompletedEventHandler openReadCompletedHandler = null;
DownloadProgressChangedEventHandler progressChangedHandler = null;
WebClient webClient = new WebClient();
webClient.DownloadProgressChanged += progressChangedHandler = (s, e) => {
ProgressPercentage = e.ProgressPercentage;
if (DownloadProgressChanged != null) { DownloadProgressChanged(this, e); }
};
webClient.OpenReadCompleted += openReadCompletedHandler = (s, e) => {
WebClient wc = s as WebClient;
wc.DownloadProgressChanged -= progressChangedHandler;
wc.OpenReadCompleted -= openReadCompletedHandler;
if (e.Error != null) {
//断网处理,5秒后重试
Error++;
GlobalMethod.SetTimeout(delegate {
Download(uri, userToken);
}, 5000);
} else {
waitingUri.Remove(uri);
loadingUri.Remove(uri);
if (!loadedUri.Contains(uri)) { loadedUri.Add(uri); }
if (OpenReadCompleted != null) { OpenReadCompleted(this, e); }
}
};
webClient.OpenReadAsync(new Uri(uri, UriKind.Relative), userToken);
}
}
SerialDownloader 

    /// <summary>
/// 下载优先级
/// </summary>
public enum DownloadPriority {
/// <summary>
/// 最高
/// </summary>
Highest = 0,
/// <summary>
/// 高
/// </summary>
High = 1,
/// <summary>
/// 普通
/// </summary>
Normal = 2,
/// <summary>
/// 低
/// </summary>
Low = 3,
/// <summary>
/// 最低
/// </summary>
Lowest = 4,
} /// <summary>
/// 串行资源下载器
/// </summary>
public class SerialDownloader : DownloadBase { /// <summary>
/// 资源下载完成
/// </summary>
public static event OpenReadCompletedEventHandler OpenReadCompleted; /// <summary>
/// 资源下载进度中触发
/// </summary>
public static event DownloadProgressChangedEventHandler DownloadProgressChanged; /// <summary>
/// 当前进度百分比
/// </summary>
public static int ProgressPercentage { get; private set; } static WebClient webClient = null;
readonly static List<string> loadingUri = new List<string>();
readonly static List<string> waitingUri = new List<string>();
/// <summary>
/// 获取当前正在下载的地址
/// </summary>
public static List<string> LoadingUri { get { return loadingUri; } }
/// <summary>
/// 获取等待下载地址队列
/// </summary>
public static List<string> WaitingUri { get { return waitingUri; } } /// <summary>
/// 为Image图片控件设置图像源
/// </summary>
/// <param name="image">目标图片</param>
/// <param name="uri">图像源地址</param>
/// <param name="isWaiting">是否等待下载完成后再赋值</param>
public static void SetImageSource(Image image, string uri, DownloadPriority priority, bool isWaiting) {
if (loadedUri.Contains(uri)) {
image.Source = GlobalMethod.GetWebImage(uri);
} else {
image.Source = null;
AddUri(uri, priority);
if (isWaiting) {
DispatcherTimer timer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(2000) };
EventHandler handler = null;
timer.Tick += handler = (s, e) => {
if (loadedUri.Contains(uri)) {
timer.Stop();
timer.Tick -= handler;
image.Source = GlobalMethod.GetWebImage(uri);
}
};
timer.Start();
}
}
} /// <summary>
/// 添加预备下载地址
/// </summary>
/// <param name="uri">图像源地址</param>
public static void AddUri(string uri, DownloadPriority priority) {
if (!waitingUri.Contains(uri)) { waitingUri.Insert((int)(((int)priority / 4d) * waitingUri.Count), uri); }
if (loadingUri.Count == 0) {
webClient = new WebClient();
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(webClient_DownloadProgressChanged);
webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(webClient_OpenReadCompleted);
webClient.OpenReadAsync(new Uri(GlobalMethod.WebPath(uri), UriKind.Relative), uri);
loadingUri.Add(uri);
}
} static void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e) {
WebClient wc = sender as WebClient;
wc.DownloadProgressChanged -= webClient_DownloadProgressChanged;
wc.OpenReadCompleted -= webClient_OpenReadCompleted;
string uri = e.UserState.ToString();
if (e.Error != null) {
//断网处理,5秒后重试
Error++;
GlobalMethod.SetTimeout(delegate {
loadingUri.Remove(uri);
AddUri(uri, DownloadPriority.Highest);
}, 5000);
} else {
loadingUri.Remove(uri);
waitingUri.Remove(uri);
loadedUri.Add(uri);
if (waitingUri.Count > 0) { AddUri(waitingUri[0], DownloadPriority.Highest); }
if (OpenReadCompleted != null) { OpenReadCompleted(sender, e); }
}
} static void webClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) {
ProgressPercentage = e.ProgressPercentage;
if (DownloadProgressChanged != null) { DownloadProgressChanged(sender, e); }
} }

Silverlight并行下载与串行下载的更多相关文章

  1. 痞子衡嵌入式:一种i.MXRT下从App中进入ROM串行下载模式的方法

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT下在App中利用ROM API进ISP/SDP模式的方法. 我们知道i.MXRT系列分为两大阵营:CM33内核的i.MXRT ...

  2. 【Java8新特性】关于并行流与串行流,你必须掌握这些!!

    写在前面 提到Java8,我们不得不说的就是Lambda表达式和Stream API.而在Java8中,对于并行流和串行流同样做了大量的优化.对于并行流和串行流的知识,也是在面试过程中,经常被问到的知 ...

  3. JDK8--07:并行流与串行流

    JDK8中,提供了并行流和串行流,使用parallel()和sequential()来处理,parallel()为并行流sequential()为串行流,两者可以相互转换,以最后一个为准 LongSt ...

  4. Java8的新特性--并行流与串行流

    目录 写在前面 Fork/Join框架 Fork/Join框架与传统线程池的区别 传统的线程池 Fork/Join框架 Fork/Join框架的使用 Java8中的并行流 写在前面 我们都知道,在开发 ...

  5. Java8新特性 并行流与串行流 Fork Join

    并行流就是把一个内容分成多个数据块,并用不同的线程分 别处理每个数据块的流. Java 8 中将并行进行了优化,我们可以很容易的对数据进行并 行操作. Stream API 可以声明性地通过 para ...

  6. 三、并行流与串行流 Fork/Join框架

    一.并行流概念: 并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流. java8中将并行进行了优化,我们可以很容易的对数据进行并行操作.Stream API可以声明性的通过pa ...

  7. Java8新特性 - 并行流与串行流

    并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流. Java8中将并行进行了优化,我们可以很容易的对数据进行并行操作.Stream API可以声明性地通过parallel()和 ...

  8. GCD的同步异步串行并行、NSOperation和NSOperationQueue一级用dispatch_once实现单例

    转:http://www.tuicool.com/articles/NVVnMn (1)GCD实现的同步异步.串行并行. ——同步sync应用场景:用户登录,利用阻塞 ——串行异步应用场景:下载等耗时 ...

  9. 【iOS开发-91】GCD的同步异步串行并行、NSOperation和NSOperationQueue一级用dispatch_once实现单例

    (1)GCD实现的同步异步.串行并行. --同步sync应用场景:用户登录,利用堵塞 --串行异步应用场景:下载等耗时间的任务 /** * 由于是异步.所以开通了子线程.可是由于是串行队列,所以仅仅须 ...

随机推荐

  1. Linux挂载硬盘出错:$LogFile indicates unclean shutdown (0, 0)

    前一次还挂载好好的,今天在挂载NTFS的分区就不行了,出现如下错误信息和提示: $LogFile indicates unclean shutdown (0, 0) Mount is denied b ...

  2. Cordova了解

    概述 Cordova让我们可以使用HTML.JS以及CSS开发跨平台App的公共部分(整个App就是一个WebView或者或者嵌入到本地组件中),与原生API的交互通过Cordova插件实现. 安装配 ...

  3. WPF那些事儿

    概述 感觉学习的东西必须做个记录,不然很快就忘掉了.现在把WPF学习过程中一些零碎的东西记录在下面,没有具体的主题,想到啥.看到啥都写在这里,算是复习一下并做个备忘吧. 1. 等待对话框 看到同事做的 ...

  4. I/O重定向与管道

    1.输出重定向 (1)>  覆盖输出 (2)>>  追加输出 (3) set -C: 禁止对已经存在文件使用覆盖重定向: 强制覆盖输出,则使用 >| set +C: 关闭上述功 ...

  5. DRBD脑裂解决方法

    1.查看主服务器 [root@master ~]# /etc/init.d/drbd status drbd driver loaded OK; device status: version: (ap ...

  6. eclipse 和myEclipse 项目导入

    经常在eclipse/myeclipse中导入web项目时,出现转不了项目类型的问题,导入后就是一个java项目. 有两种情况: 一.eclipse无法识别其他eclipse的web项目 解决步骤: ...

  7. js问题学习

    1.前言为了node.js做准备,js的基本功还是很重要的.所以正值1024程序员节的时候所以找了些题目,整理了一下知识点.这篇文章感觉代码太多,难免枯燥,所以文章最后留了个彩蛋给读者. 2.简单回调 ...

  8. jQuery 随滚动条滚动效果 (适用于内容页长文章)

    直接入题! 当内容页比较长的时候,网站右侧一直是空白,不如放点有用的东西给用户看,最好不要放广告,因为那样很邪恶,你懂的. 好吧,昨天写了这个东西,jQuery滚动随动区块,代码如下: //侧栏随动 ...

  9. codevs 1913 数字梯形问题 费用流

    题目链接 给你一个数字梯形, 最上面一层m个数字, 然后m+1,......m+n-1个. n是层数. 在每个位置, 可以向左下或右下走.然后让你从最顶端的m个数字开始, 走出m条路径, 使得路过的数 ...

  10. 人生第一场组队赛---2014.8 zju monthly

    暑期集训中段就组了队,不过一直没机会打比赛 昨天kitkat突然发现了zju要搞月赛,我想了一下题目对于我这种渣实在是有点难,于是想到干脆打一次组队赛吧,跟队友商量了一下也同意了 12点---17点  ...