使用C#的Delegate机制实现资源的异步读取的类

2024-08-20 16:08

本文主要是介绍使用C#的Delegate机制实现资源的异步读取的类,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

制作网页网游,常常需要从Server端临时下载一个资源进来,然后读取,通常使用WWW下载AssetBundle的方法来实现。而下载过程需要时间,不可能立即完成,这通常需要提供下载需求的用户自己实现同步的机制,比较麻烦,而且需要重复劳动。因此我想提供一个简单的资源下载管理的类,这个类大概提供以下的功能:

1提供一个简单的异步加载的回调机制。调用这个类的一个函数,提供一个资源下载请求,接到请求后,这个类开始下载这个资源,当资源完成后,就调用用户所提供的回调函数,通知用户下载已经完成,这时用户可以选择如何处理下载完的对象。

2.用户提出请求时,可以提供一个自定义的参数,这个参数在回调函数中,作为参数传入,这样方便用户传输一些这个资源特定的信息,方便在同一个回调函数中处理不同种类的资源。

3.可以多次请求同一资源的下载请求,但不会造成实际的多次下载。而会直接把之前下载完成后的资源返回。

下面是这个类的实现代码:

using UnityEngine;

using System;

using System.Collections.Generic;


public class MyResourceManager : MonoBehaviour

{





public delegate void DownFinishDelegate (WWW wwwObj,object customParam);



public class WWWRequest

{

public string requestURl;

public DownFinishDelegate calbackFun;

public WWW wwwObject = null;

public bool bHasDeal = false;

public List customParams = new List();



public WWWRequest(){}

public WWWRequest (string url, DownFinishDelegate cbFun,object customParam=null)

{

requestURl = url;

calbackFun = new DownFinishDelegate (cbFun);

wwwObject = new WWW (url);

customParams.Add(customParam);





}

}



//WWW Request List

private Dictionary m_WWWMap = new Dictionary ();





public void AddDownRequest (string url, DownFinishDelegate callBackFun,object customParam=null)

{

if(url != "")

{

//增加新的资源下载需求

if (!m_WWWMap.ContainsKey (url))

{

m_WWWMap.Add (url, new WWWRequest (url, callBackFun,customParam));



}

else

{

//已经提交相同请求,但是没有下载完成

if(!m_WWWMap[url].wwwObject.isDone)

{

m_WWWMap[url].calbackFun += callBackFun;

m_WWWMap[url].customParams.Add(customParam);



}

//已下载资源,直接调用回调函数

else

{

callBackFun.Invoke (m_WWWMap[url].wwwObject,customParam);

}



}

}

}





// Use this for initialization

void Start ()

{



}



// Update is called once per frame

void Update ()

{



foreach (KeyValuePair wwwPair in m_WWWMap)

{

WWWRequest wwwReq = wwwPair.Value;

//如果尚未调用回调,并且下载完成,则调用

if ((!wwwReq.bHasDeal) && wwwReq.wwwObject.isDone)

{

//print("DelegationCount:"+wwwReq.calbackFun.GetInvocationList().GetLength(0));

for(int i=0;i<wwwreq.calbackfun.getinvocationlist().getlength(0);i++)

{
((DownFinishDelegate)wwwReq.calbackFun.GetInvocationList()[i]).Invoke(wwwReq.wwwObject,wwwReq.customParams[i]);

}

wwwReq.bHasDeal = true;

}

}

}







}
复制代码
关于实现,有以下一些考虑和说明:

1. 这个类继承自脚本的类MonoBehaviour,这样主要是为了可以被放到主循环里,在Update函数检查每个请求是否已经下载完成,这样需要在场景中添加一个GameObject,将这个脚本附加到上边。

2.回调托管函数的原型声明为:

public delegate void DownFinishDelegate (WWW wwwObj,object customParam);

是一个无返回值,带有两个参数的函数,第一个参数是下载的WWW对象,第二个是自定义参数。

3.类中包含一个内部类WWWRequest,这个类代表一种资源的下载请求,而不是一次。这里的一种是以一个URL来区分的,也就是说可以多次请求同一个URL资源下载,但是可以提供不同的回调和自定义参数,这多次的下载请求都属于同一个WWWRequest,这样提供了更多的灵活性,也不需要重复下载同一个资源多次。为了实现这个功能,使用了C#中的Dictionary类型,这个字典类型类似于C++中的map,由一个键值索引一个值,这个键值就是url的字符串。值就是这个WWWRequest对象。

这个对象中包含了以下属性:

url字符串:
string requestURl
复制代码
回调函数的托管对象:
DownFinishDelegate calbackFun
复制代码
资源下载所用到的WWW对象:WWW wwwObject

标示是否下载完成的旗标:bool bHasDeal

自定义参数列表:List customParams

因为一个托管对象,可以加载多个托管函数,因此这里只使用一个托管对象,而自定义参数需要提供一个列表。每个托管的回调函数按顺序一一对应列表中的参数。

3.AddDownRequest就是提供下载资源请求所需要调用的函数。实现比较简单,先检查在Dictonary里是否已有这个资源的下载请求,如果没有增添一个新的请求,创建一个WWWRequest对象加入到字典中。

如果已有,那么检查当前的状态,如果已经下载完成,则直接调用用户提供的回调函数。

如果还没下载完成,就在字典中已经创建的WWWRequest中的托管对象 和参数列表中相应都增加新的一项,等待下载完成后调用。

4.在Update函数中,遍历检查每个WWWRequest中的WWW对象的当前状态,如果有完成的,则依次调用每个注册到这个WWWRequest的回调函数,传入对应的自定义参数。

调用完成后,将旗标置位,防止下次更新再调用。

【使用方法】:

要使用这个类,首先需要找到场景中的资源管理的GameObject,并且获得脚本类对象。

1.MyResourceManager resMgr = (MyResourceManager)GameObject.Find("MyResourceManager").GetComponent("MyResourceManager") ;

然后提出下载请求:

1.resMgr.AddDownRequest("http://"+GlobalConfig.GetConnectIP()+"/AssetBundleResource/Terrain/Terrain3.unity3d",DownFinishDelegate,null);

这里第一个参数就是下载的Url,第二个是回调函数,自定义参数因为这里没用到,传入null。

然后需要声明回调处理函数:

public void DownFinishDelegate (WWW wwwParam,object customParam)

{

wwwObj = wwwParam;

}
复制代码
这个函数在资源下载完成后会被调用,这里的处理逻辑比较简单,只是简单保存下下载的WWW对象,以便之后使用其中的assetBundle对象。

这篇关于使用C#的Delegate机制实现资源的异步读取的类的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1090535

相关文章

使用Python实现IP地址和端口状态检测与监控

《使用Python实现IP地址和端口状态检测与监控》在网络运维和服务器管理中,IP地址和端口的可用性监控是保障业务连续性的基础需求,本文将带你用Python从零打造一个高可用IP监控系统,感兴趣的小伙... 目录概述:为什么需要IP监控系统使用步骤说明1. 环境准备2. 系统部署3. 核心功能配置系统效果展

Python实现微信自动锁定工具

《Python实现微信自动锁定工具》在数字化办公时代,微信已成为职场沟通的重要工具,但临时离开时忘记锁屏可能导致敏感信息泄露,下面我们就来看看如何使用Python打造一个微信自动锁定工具吧... 目录引言:当微信隐私遇到自动化守护效果展示核心功能全景图技术亮点深度解析1. 无操作检测引擎2. 微信路径智能获

使用Java将各种数据写入Excel表格的操作示例

《使用Java将各种数据写入Excel表格的操作示例》在数据处理与管理领域,Excel凭借其强大的功能和广泛的应用,成为了数据存储与展示的重要工具,在Java开发过程中,常常需要将不同类型的数据,本文... 目录前言安装免费Java库1. 写入文本、或数值到 Excel单元格2. 写入数组到 Excel表格

redis中使用lua脚本的原理与基本使用详解

《redis中使用lua脚本的原理与基本使用详解》在Redis中使用Lua脚本可以实现原子性操作、减少网络开销以及提高执行效率,下面小编就来和大家详细介绍一下在redis中使用lua脚本的原理... 目录Redis 执行 Lua 脚本的原理基本使用方法使用EVAL命令执行 Lua 脚本使用EVALSHA命令

C#如何调用C++库

《C#如何调用C++库》:本文主要介绍C#如何调用C++库方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录方法一:使用P/Invoke1. 导出C++函数2. 定义P/Invoke签名3. 调用C++函数方法二:使用C++/CLI作为桥接1. 创建C++/CL

Python中pywin32 常用窗口操作的实现

《Python中pywin32常用窗口操作的实现》本文主要介绍了Python中pywin32常用窗口操作的实现,pywin32主要的作用是供Python开发者快速调用WindowsAPI的一个... 目录获取窗口句柄获取最前端窗口句柄获取指定坐标处的窗口根据窗口的完整标题匹配获取句柄根据窗口的类别匹配获取句

Java 中的 @SneakyThrows 注解使用方法(简化异常处理的利与弊)

《Java中的@SneakyThrows注解使用方法(简化异常处理的利与弊)》为了简化异常处理,Lombok提供了一个强大的注解@SneakyThrows,本文将详细介绍@SneakyThro... 目录1. @SneakyThrows 简介 1.1 什么是 Lombok?2. @SneakyThrows

在 Spring Boot 中实现异常处理最佳实践

《在SpringBoot中实现异常处理最佳实践》本文介绍如何在SpringBoot中实现异常处理,涵盖核心概念、实现方法、与先前查询的集成、性能分析、常见问题和最佳实践,感兴趣的朋友一起看看吧... 目录一、Spring Boot 异常处理的背景与核心概念1.1 为什么需要异常处理?1.2 Spring B

Python位移操作和位运算的实现示例

《Python位移操作和位运算的实现示例》本文主要介绍了Python位移操作和位运算的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1. 位移操作1.1 左移操作 (<<)1.2 右移操作 (>>)注意事项:2. 位运算2.1

如何在 Spring Boot 中实现 FreeMarker 模板

《如何在SpringBoot中实现FreeMarker模板》FreeMarker是一种功能强大、轻量级的模板引擎,用于在Java应用中生成动态文本输出(如HTML、XML、邮件内容等),本文... 目录什么是 FreeMarker 模板?在 Spring Boot 中实现 FreeMarker 模板1. 环