思路清晰后仅仅只需百来行代码便可轻松编写出一套完整的资源动态下载组件- 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. 标准C++的string类使用

    原文:http://www.cnblogs.com/xFreedom/archive/2011/05/16/2048037.html 要想使用标准C++中string类,必须要包含#include & ...

  2. Vim 扩展工具 vim-ide (转)

    通过简单的配置文件将 vim 打造成专业 ide,支持 mac linux cygwin.看过数篇 vim 配置文件,必要时去定制vim 的插件,将 vim 的 ide 用户体验尽量做到极致. 使用范 ...

  3. winform使用xml作为数据源

    1.新建窗体应用程序 2.拖放DataGridView 3.在bin\Debug中放入XML文件 using System; using System.Collections.Generic; usi ...

  4. 消息机制JMS

    消息机制JMS http://wenku.baidu.com/link?url=5FiNu_HP3lUFKhePmfCUPE09DV_f9-tsQ4NpWtKxHYphxAglzsjg3XSM8Sz6 ...

  5. J2SE知识点摘记(三)

    1.         在java只允许单继承,而不允许多重继承,也就是说一个子类只能有一个父类.但在java中却允许多层继承. 2.         非内部Class只能被public或者defaul ...

  6. Oracle EBS-SQL (PO-3):检查期间手工下达的采购订单记录数.sql

    SELECT DECODE(pda.req_distribution_id,'','手工','自动创建') 下达方式, --pda.req_distribution_id                ...

  7. [Django 1.5] Django 开发学习资源链接

    jQuery : jQuery API introduction:http://api.jquery.com/ jQuery plugins: http://benalman.com/projects ...

  8. 客户端数据持久化解决方案: localStorage

    客户端数据持久化解决方案: localStorage localStorage主要用来替代cookie,解决cookie读写困难.容量有限的问题. localStorage有以下几个特点 localS ...

  9. Linux进程间通信——使用信号量

    这篇文章将讲述别一种进程间通信的机制——信号量.注意请不要把它与之前所说的信号混淆起来,信号与信号量是不同的两种事物.有关信号的更多内容,可以阅读我的另一篇文章:Linux进程间通信——使用信号.下面 ...

  10. linux 进程(二) --- 进程的创建及相关api

    一.进程的创建fork()函数  由fork创建的新进程被称为子进程(child process).该函数被调用一次,但返回两次.两次返回的区别是子进程的返回值是0,而父进程的返回值则是 新子进程的进 ...