silverlight游戏设计(二)资源管理篇(下)--资源的状态通知、管理与缓存

在上篇中,我们实现了一个带有池化、并发连接限制能力的资源下载器,虽然这个下载器能够使我们的游戏动态加载资源并在加载完毕/失败后调用回调方法。但是还是缺乏一些智能。比如我要加载一个game_role_petegg.zip的资源包,如我们有需求:
1.对已经下载过的资源不再重复下载。
2.下载过的资源要缓存,一方面存在内存中,一方面存在isolatedstorage中。
实现这些功能会极大的提高用户体验,所我们有必要设计一个带有缓存控制能力的资源管理器。
复用已有的DownloadDelegater
搞开发的嘛,不可能每一个需求都单独写一片代码,这要将对象的职责分离清楚,复用还是很容易的。
我们定义需求接口:
public interface IWebClientResourceService { void Load(Uri uri, DownloadResultEventHandler callback); void PutIsolatedStorageToMemoryCache(Uri uri); void PutMemoryCacheToIsolatedStorage(Uri uri); void RemoveCache(Uri uri); }

Load方法会下载指定uri的资源,如果之前已经在下载过就不会重复下载。
PutIsolatedStorageToMemoryCache将隔离存储中的数据加载到内存中。
PutMemoryCacheToIsolatedStorage将内存数据保存到隔离存储。
下面通过组合的方式复用之前的DownloadDelegater。
imagesilverlight游戏设计(二)资源管理篇(下)--资源的状态通知、管理与缓存
imageimagesilverlight游戏设计(二)资源管理篇(下)--资源的状态通知、管理与缓存
imageimagesilverlight游戏设计(二)资源管理篇(下)--资源的状态通知、管理与缓存imageimagesilverlight游戏设计(二)资源管理篇(下)--资源的状态通知、管理与缓存WebClientResourceService namespace Sopaco.Silverlight.Insfrastructure.Net.DownloadActivator { public class WebClientResourceService : Sopaco.Silverlight.Insfrastructure.Net.DownloadActivator.IWebClientResourceService { public static readonly WebClientResourceService Instance; static WebClientResourceService() { Instance = new WebClientResourceService(); } private Dictionary _resourceCacher = new Dictionary(); private DownloadDelegater _downloadDelegater = new DownloadDelegater(); private object _locker_ResourceCacher = new object(); public void Load(Uri uri, DownloadResultEventHandler callback) { #region 检查是否已经有缓存 lock (_locker_ResourceCacher) { if (_resourceCacher.ContainsKey(uri)) { if (callback != null) { var task = _resourceCacher[uri]; callback(task.CloneStream, task.Status); } return; } _resourceCacher[uri] = new DownloadTask() { Uri = uri, Stream = null, Status = DownloadStatus.UnStarted }; } #endregion #region 使用下载器下载 _downloadDelegater.Download(uri, (stream, status) => { _disibledevent=>if(callback != null) callback(stream, status); }); if (_resourceCacher[uri].Status == DownloadStatus.UnStarted)//防止过快下载而使状态不同步 { _resourceCacher[uri].Status = DownloadStatus.Running; } #endregion } /// /// 移除缓存 /// 未防止缓存内容过大导致内存持续消耗,应该适当调用此方法移出缓存(或者存放在隔离存储中?) /// public void RemoveCache(Uri uri) { lock (_locker_ResourceCacher) { if (_resourceCacher.ContainsKey(uri)) { var cacheObj = _resourceCacher[uri]; if(_resourceCacher.Remove(uri)) { cacheObj.Dispose(); } else { System.Diagnostics.Debug.WriteLine("移除资源异常:无法移除资源@" + System.Reflection.MethodInfo.GetCurrentMethod().ToString()); } } } } /// /// 将一个资源缓存到隔离存储中 /// ///
public void PutMemoryCacheToIsolatedStorage(Uri uri) { if(_resourceCacher.ContainsKey(uri)) { IsolateStorageRespository.Instance.AddWithOverwrite(uri.ToString(), _resourceCacher[uri]); } } /// /// 从隔离存储中将一个资源缓存起来 /// ///
public void PutIsolatedStorageToMemoryCache(Uri uri) { if (_resourceCacher.ContainsKey(uri)) { var cache = IsolateStorageRespository.Instance.Get(uri.ToString()); if(cache != null) { _resourceCacher[uri] = cache; } } } private void _disibledevent=>= status; _resourceCacher[uri].Stream = stream; } } }

进一步使用
上面的WebClientResourceService功能还是有些“大一统”,我们可以进一步针对一些特定资源进行应用。
示例需求:对于图片资源包和一些零散的没有放到资源包里的图片资源,一旦下载下来将其放到隔离存储中,下次再需要下载此图片时就直接从隔离存储中取得(如果资源有更新的话将隔离存储中的数据清除就ok)。
GameImageResService namespace Sopaco.Silverlight.GameFramewrok.GameRes { /// /// 应用WebClientResourceService定制的一个游戏资源服务模块 /// public class GameImageResService { #region make it a singleton public static readonly GameImageResService Instance; static GameImageResService() { Instance = new GameImageResService(); } public GameImageResService() { } #endregion private static readonly string IMG_ZIP_XML = "resconfig.xml"; private WebClientResourceService _resourceService = WebClientResourceService.Instance; private Dictionary _imageCache = new Dictionary(); private Dictionary _namedImageCache = new Dictionary(); /// /// 图片资源 /// public void GetBitmapImage(Uri uri, Action callback) { if(_imageCache.ContainsKey(uri)) { callback(_imageCache[uri]); return; } _resourceService.Load(uri, (stream, status) => { if(status == DownloadStatus.Completed) { var image = new BitmapImage(); image.SetSource(stream); _imageCache[uri] = image; _resourceService.PutMemoryCacheToIsolatedStorage(uri);//图片资源由GameResService托管,将WebClientResourceService中的缓存持久化 callback.ExecuteSecurity(image); } else { #if DEBUG throw new Exception("error in resource downloading"); #endif } }); } /// /// 载入一个zip资源包中的图片资源 /// /*配置文件格式 * resconfig.xml * * * * * #endregion */ public void GetBitmapImageInZip(Uri uri, Action _disibledevent=>=> { if(status != DownloadStatus.Completed) { #if DEBUG throw new Exception("error in download resource"); #endif } _disibledevent=>= new StreamResourceInfo(stream, null); using (var reader = new StreamReader(Application.GetResourceStream(info, new Uri(IMG_ZIP_XML, UriKind.Relative)).Stream)) { var xmlReader = XmlReader.Create(reader); while(xmlReader.Read()) { if(xmlReader.IsStartElement("ImgResSection")) { while(xmlReader.Read()) { if(xmlReader.IsStartElement("Image")) { xmlReader.MoveToAttribute("key"); xmlReader.ReadAttributeValue(); string imgKey = xmlReader.Value; xmlReader.MoveToAttribute("uri"); xmlReader.ReadAttributeValue(); var targetUri = new Uri(xmlReader.Value, UriKind.RelativeOrAbsolute); var bitmapStream = Application.GetResourceStream(info, targetUri).Stream; var image = new BitmapImage(); image.SetSource(bitmapStream); _namedImageCache[imgKey] = image; } } } } } _disibledevent=>#region zip图片资源包由GameResService托管,将WebClientResourceService中的缓存持久化 _resourceService.PutMemoryCacheToIsolatedStorage(uri); #endregion }); } public BitmapImage GetImageByUri(Uri uri) { if (!_imageCache.ContainsKey(uri)) return null; return _imageCache[uri]; } public BitmapImage GetImageBySpecialName(string key) { if(!_namedImageCache.ContainsKey(key)) return null; return _namedImageCache[key]; } } }

本文源码下载
imageimagesilverlight游戏设计(二)资源管理篇(下)--资源的状态通知、管理与缓存 最后祝大家圣诞快乐Merry Christmas!imageimagesilverlight游戏设计(二)资源管理篇(下)--资源的状态通知、管理与缓存
Tags: 

延伸阅读

最新评论

发表评论