思路清晰后仅仅只需百来行代码便可轻松编写出一套完整的资源动态下载组件- 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. vbox下安装 linux 64 bit出现“kernel requires an x86_64 cpu

        今天在vbox下安装linux 64bit出现"kernel requires an x86_64 cpu, but only detected "的错误,网上有很多文章介 ...

  2. Mac下Mysql启动异常["ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)"]

    在mac下使用brew安装mysql,之前没有使用过,今天启动的时候发现启动不了 huijundeMacBook-Pro:bin huijunzhang$ mysql ERROR (HY000): C ...

  3. c++11: <thread>学习

    <thread>头文件中包含thread类与this_thread命名空间,下面逐一介绍. thread类 1. 构造函数 (1)默认构造函数 thread() noexcept; 默认构 ...

  4. nginx1.9.4 +php 5.5.29+yii2.0配置手册

    nginx1.9.4 +php 5.5.29+yii2.0配置手册 目录 一.    php5.5.29安装配置    2 二.    nginx1.9.4安装配置    2 三.    yii2.0 ...

  5. jQuery实现逐字输入效果

    之前做了个测试小游戏(姑且叫游戏吧)为了增加神秘性,就想给她加个逐字输入效果:刚好在网上找到一个挺好用的,于是就发扬拿来主义:按照自己的喜好做了一丢丢的修改(勉强算是吧\( ̄︶ ̄)> ). 代码 ...

  6. Java getResourceAsStream返回为空的问题

    使用 getResourceAsStream("helloworld.propterties") 读取文件的stream,返回一直为空,试这把.properties文件放在 很多路 ...

  7. mac下配置java环境

    1.tomcat配置 http://www.cnblogs.com/freeyiyi1993/p/3436368.html 2.下载eclipse和jdk安装  jdk去oracle网站下载

  8. C++箴言:理解 new-handler的行为

    当 operator new 不能满足一个内存分配请求时,它抛出一个 exception(异常).很久以前,他返回一个 null pointer(空指针),而一些比较老的编译器还在这样做.你依然能达到 ...

  9. java常量池理解

    String类两种不同的创建方式 String s1 = "zheng"; //第一种创建方式 String s2 = new String("junxiang" ...

  10. hdu - 1083 - Courses

    题意:有P门课程,N个学生,每门课程有一些学生选读,每个学生选读一些课程,问能否选出P个学生组成一个委员会,使得每个学生代言一门课程(他必需选读其代言的课程),每门课程都被一个学生代言(1 <= ...