国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

U3D客戶端框架之支持?jǐn)帱c(diǎn)續(xù)傳的文件下載器實(shí)現(xiàn)方案

這篇具有很好參考價(jià)值的文章主要介紹了U3D客戶端框架之支持?jǐn)帱c(diǎn)續(xù)傳的文件下載器實(shí)現(xiàn)方案。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

一、功能設(shè)計(jì)

文件下載器的作用

????????文件下載器是應(yīng)用程序的基礎(chǔ)模塊,為應(yīng)用程序與外部網(wǎng)絡(luò)交互提供了必要的橋梁。該模塊設(shè)計(jì)初衷是為了熱更新過程中,下載CDN站點(diǎn)上的文件資源,所以下載器會(huì)驗(yàn)證 要下載的文件是否存在于CDN中。如果存在允許下載器繼續(xù)工作;如果不存在會(huì)跳過本地下載。做這層檢測(cè)是為了安全性考慮,不允許隨意下載網(wǎng)絡(luò)資源。如果有需求可以跳過這層檢測(cè)。

什么是斷點(diǎn)續(xù)傳

????????下載文件時(shí),不必重頭開始下載,而是從上次中斷的位置繼續(xù)下載,這樣的功能就叫做斷點(diǎn)續(xù)傳。

斷點(diǎn)續(xù)傳的作用

????????在下載文件的過程中,打斷文件下載的原因有很多,比如網(wǎng)絡(luò)不穩(wěn)定,導(dǎo)致下載,中斷如果沒有斷點(diǎn)續(xù)傳功能的話,中斷之后需要重新開始下載。例如一個(gè)文件有100M大小,我下載了99M,馬上就要下載完成了,這是突然網(wǎng)絡(luò)中斷導(dǎo)致下載失敗了,我重新開始下載的時(shí)候發(fā)現(xiàn)又需要重新開始下載,這時(shí)候是不是會(huì)感覺心態(tài)崩了,如果有了斷點(diǎn)續(xù)傳功能的話,我下載了99M,即使網(wǎng)絡(luò)中斷,重連之后我的下載依舊是從99M的位置開始下載,這樣給用戶的體驗(yàn)就很棒了。

斷點(diǎn)續(xù)傳實(shí)現(xiàn)思路

1. 在下載文件的時(shí)候我們會(huì)先創(chuàng)建一個(gè)與下載文件對(duì)應(yīng)的以.temp為后綴的臨時(shí)文件, 下載的文件數(shù)據(jù)會(huì)寫入這個(gè)臨時(shí)文件中。
2. 每次開始下載的時(shí)候會(huì)檢查是否存在需下載文件的臨時(shí)文件,如果存在,便從該文件數(shù)據(jù)長(zhǎng)度的地方開始下載寫入。
3. 下載完成后便將臨時(shí)文件移動(dòng)到目標(biāo)下載目錄。
?

二、代碼設(shè)計(jì)

下載器在物理結(jié)構(gòu)上切分成了4個(gè)文件模塊,每個(gè)模塊各司其職。

文章在講解的時(shí)候會(huì)挑選模塊內(nèi)的主要的函數(shù)來講解。

文章格式按照

? ? ? ? 模塊中文名 類名

? ? ? ? ? ? ? ? 函數(shù):函數(shù)中文名 函數(shù)名

? ? ? ? ? ? ? ? ? ? ? ? 具體作用解釋。

具體的函數(shù)實(shí)現(xiàn)可以去改模塊底部完整代碼部分,根據(jù)函數(shù)名搜索該函數(shù)即可。函數(shù)里也對(duì)每一句話添加了注釋。如果還是不懂的可以私信我。

下載器回調(diào) DownloadHandler

?+ 函數(shù):下載數(shù)據(jù)回調(diào)?OnReceiveDataAction

????????OnReceiveDataAction重寫了DownloadHandlerScript內(nèi)的函數(shù)。其主要作用就是我們程序內(nèi)部需要拿到下載的進(jìn)度數(shù)據(jù)。

DownloadHandler.cs 完整代碼

    public class DownloadHandler : DownloadHandlerScript
    {
        //下載速度限制1024KB
        const int DownLoadKB = 1024;

        //初始化下載句柄,定義每次下載的數(shù)據(jù)上線為 DownLoadKB KB
        //單位:字節(jié) ,字節(jié) = 1024字節(jié) * DownLoadKB (轉(zhuǎn)換成字節(jié)單位)
        public DownloadHandler() : base(new byte[1024 * DownLoadKB])
        {

        }

        //接收到數(shù)據(jù)的委托
        public BaseAction<byte[], int> OnReceiveDataAction;

        protected override bool ReceiveData(byte[] data, int dataLength)
        {
            if (null == data || dataLength == 0)
                return false;

            OnReceiveDataAction?.Invoke(data, dataLength);
            return true;
        }
        
    }

單文件下載器 DownloadRoutine

- 函數(shù):下載存盤 Save

下載文件中會(huì)調(diào)用,會(huì)檢查當(dāng)前內(nèi)存緩存是否達(dá)到數(shù)據(jù)落地要求,如果達(dá)到,往硬盤里寫入一次文件。

- 函數(shù):斷點(diǎn)下載?Download(string url, uint beginPos)

斷點(diǎn)下載函數(shù),從指定字節(jié)處下載這個(gè)文件。

- 函數(shù):開始下載 BeginDownload

檢查下載目錄是否存在,不存在則創(chuàng)建;保存下載文件MD5;拼接真實(shí)鏈接;

- 函數(shù):內(nèi)部下載?DownloadInner

有相同文件比較MD5是否相同,若不同刪除重新下載;定位斷點(diǎn)續(xù)傳文件下載位置;

+ 函數(shù):下載 Download(string url)

從頭下載文件

+ 函數(shù):開始下載 BeginDownload

外部調(diào)用函數(shù),會(huì)把相對(duì)url、資源信息、更新、完成回調(diào)都傳入給該對(duì)象

+ 函數(shù):更新 OnUpdate

下載中回調(diào);下載失敗重試;下載完成操作;

+ 函數(shù):重置?Reset

關(guān)閉WebRequest下載器;接觸文件占用;變量重置;

+ 函數(shù):釋放 Dispose

對(duì)象或程序生命周期結(jié)束時(shí)調(diào)用,內(nèi)部調(diào)用了 Reset還原類內(nèi)類內(nèi)成員的狀態(tài)。

DownloadRoutine.cs 完整代碼

    //文件下載器
    public class DownloadRoutine:IDisposable
    {
        //Web請(qǐng)求(存了web的連接)
        private UnityWebRequest m_UnityWebRequest = null;

        //文件流(寫入文件使用)
        private FileStream m_FileStream;

        //當(dāng)前等待寫入磁盤的大?。ǔ^閾值才會(huì)把這一部分寫入文件的尾部)
        private int m_CurrWaitFlushSize = 0;

        //上次寫入的大?。ㄉ洗螌懭胛募鞯娜看笮。?        private int m_PrevWriteSize = 0;

        //文件總大小
        private ulong m_TotalSize;

        //當(dāng)前下載的大小(下載了多少了)
        private ulong m_CurrDownloadSize = 0;

        //起始位置
        private uint m_BeginPos = 0;

        //當(dāng)前下載文件的鏈接(url)
        private string m_CurrFileUrl;

        //下載到的本地路徑
        private string m_DownloadLocalFilePath;

        //下載中的委托(string:url,ulong:下載的大小,float:下載百分比)
        private BaseAction<string, ulong, float> m_OnUpdate;

        //下載完畢回調(diào)
        private BaseAction<string, DownloadRoutine> m_OnComplete;

        //當(dāng)前的資源包信息(*:是信息,不是文件實(shí)體;如果不是資源包,是其他的文件怎么辦?比如mp4就不能下載了是嗎?必須要把資源壓到ab包里)
        private AssetBundleInfoEntity m_CurrAssetBundleInfo;

        //當(dāng)前重試次數(shù)
        private int m_CurrRetry = 0;

        //上次重試時(shí)間
        private float m_PrevRetryTime = 0;

        //下載句柄(這個(gè)也是繼承unity的然后自己封裝的一層)
        private DownloadHandler m_DownloadHandler;

        /*
         * 功能:保存字節(jié)
         * buffer:文件流
         * downloadComplete:是否下載完成
         * bufferCount:文件流的總長(zhǎng)度(單位:字節(jié))
         */
        private void Save(byte[] buffer, bool downloadComplete = false, int bufferCount = 0)
        {
            if (null == buffer)
                return;

            //len是文件流的總長(zhǎng)度
            int len = buffer.Length;

            //文件流的總長(zhǎng)度-上一次寫入的大小 = 這次要寫入多少?
            int count = len - m_PrevWriteSize;

            //m_FileStream?.Write(buffer,m_PrevWriteSize,count);
            //把偏移寫入的方法,換成全量寫入了?
            m_FileStream?.Write(buffer, 0, bufferCount);

            m_PrevWriteSize = len;

            m_CurrWaitFlushSize += count;

            //內(nèi)存中下載的文件大小超過了 FlushSize(2048k)*1024 =多少字節(jié)。 到達(dá)指定的字節(jié)數(shù) || 下載完成 直接把流數(shù)據(jù)Append到文件尾部 
            if (m_CurrWaitFlushSize >= GameEntry.Download.FlushSize * 1024 || downloadComplete)
            {
                m_CurrWaitFlushSize = 0;

                //內(nèi)存緩沖區(qū)中的數(shù)據(jù)流,立即寫入磁盤
                m_FileStream.Flush();
            }
        }

        //接受到數(shù)據(jù)后(接受到網(wǎng)絡(luò)流中的數(shù)據(jù)后,會(huì)回調(diào)應(yīng)用層,然后應(yīng)用層會(huì)毀掉我們自己封裝的這個(gè)函數(shù))
        //沒下載完成
        private void DownloadHandlerReceiveDataCallBack(byte[] buffer, int length)
        {
            Save(buffer, false, length);
        }


        /*
         * 函數(shù)功能:下載
         * url:文件鏈接
         * beginPos:該文件的起始下載位置 單位:字節(jié)(斷點(diǎn)續(xù)傳功能使用)
         */
        public void Download(string url, uint beginPos)
        {
            //開啟web Request
            m_UnityWebRequest = UnityWebRequest.Get(url);

            //實(shí)例化下載器
            m_DownloadHandler = new DownloadHandler();

            //注冊(cè)下載器回調(diào)
            m_DownloadHandler.OnReceiveDataAction += DownloadHandlerReceiveDataCallBack;

            //m_UnityWebRequest內(nèi)的下載器使用自定義的下載器
            m_UnityWebRequest.downloadHandler = m_DownloadHandler;

            //下載器釋放的時(shí)候 webRequest 也 跟著釋放
            m_UnityWebRequest.disposeDownloadHandlerOnDispose = true;

            //定位下載的位置,從文件的哪部分開始下載(單位:字節(jié))
            string headerValue = string.Format("bytes={0}-", beginPos.ToString());
            m_UnityWebRequest.SetRequestHeader("Range", headerValue);
            
            //發(fā)起請(qǐng)求
            m_UnityWebRequest.SendWebRequest();
        }

        public void Download(string url)
        {
            //開啟web Request
            m_UnityWebRequest = UnityWebRequest.Get(url);

            //實(shí)例化下載器
            m_DownloadHandler = new DownloadHandler();

            //注冊(cè)下載器回調(diào)
            m_DownloadHandler.OnReceiveDataAction += DownloadHandlerReceiveDataCallBack;

            //m_UnityWebRequest內(nèi)的下載器使用自定義的下載器
            m_UnityWebRequest.downloadHandler = m_DownloadHandler;

            //下載器釋放的時(shí)候 webRequest 也 跟著釋放
            m_UnityWebRequest.disposeDownloadHandlerOnDispose = true;

            //發(fā)起請(qǐng)求
            m_UnityWebRequest.SendWebRequest();
        }

        //進(jìn)行下載
        private void BeginDownload()
        {
            //目錄
            string directory = Path.GetDirectoryName(m_DownloadLocalFilePath);
            
            //文件不存在,就創(chuàng)建一個(gè)
            if (!Directory.Exists(directory))
            {
                Directory.CreateDirectory(directory);
            }

            m_FileStream = new FileStream(m_DownloadLocalFilePath,FileMode.Create,FileAccess.Write);

            PlayerPrefs.SetString(m_CurrFileUrl,m_CurrAssetBundleInfo.MD5);

            //開始下載
            string url = string.Format("{0}{1}", GameEntry.Data.SysDataManager.CurrChannelConfig.RealSourceUrl, m_CurrFileUrl);
            Download(url);
        }

        //內(nèi)部下載
        private void DownloadInner()
        {
            //本地是否有該文件
            if (File.Exists(m_DownloadLocalFilePath))
            {
                //驗(yàn)證md5,如果本地文件的md5和cdn的md5不一致,刪除本地文件,重新下載
                if (PlayerPrefs.HasKey(m_CurrFileUrl))
                {
                    //驗(yàn)證
                    if (!PlayerPrefs.GetString(m_CurrFileUrl).
                        Equals(m_CurrAssetBundleInfo.MD5, StringComparison.CurrentCultureIgnoreCase))
                    {
                        //本地文件和cdn md5不一致 刪除本地文件
                        File.Delete(m_DownloadLocalFilePath);
                        BeginDownload();
                    }
                    else
                    {
                        //文件一致,打開文件
                        m_FileStream = File.OpenWrite(m_DownloadLocalFilePath);
                        
                        //光標(biāo)定位到文件的最后
                        m_FileStream.Seek(0,SeekOrigin.End);

                        //開始位置設(shè)置成文件的長(zhǎng)度
                        m_BeginPos = (uint)m_FileStream.Length;

                        //開始下載,直接成功(只是走了一邊下載的流程,其實(shí)根本沒下載)
                        string url = string.Format("{0}{1}",GameEntry.Data.SysDataManager.CurrChannelConfig.RealSourceUrl,m_CurrFileUrl);
                        Download(url,m_BeginPos);
                    }
                }
            }
            else
            {
                BeginDownload();
            }
        }

        //開始下載
        public void BeginDownload(string url, AssetBundleInfoEntity assetBundleInfoEntity,
                                    BaseAction<string, ulong, float> onUpdate = null, 
                                    BaseAction<string, DownloadRoutine> onComplete = null)
        {
            m_CurrFileUrl = url;

            m_CurrAssetBundleInfo = assetBundleInfoEntity;

            m_OnUpdate = onUpdate;

            m_OnComplete = onComplete;

            m_DownloadLocalFilePath = string.Format("{0}/{1}",GameEntry.Resource.LocalFilePath,m_CurrFileUrl);

            //如果本地有這個(gè)文件,先刪除
            if (File.Exists(m_DownloadLocalFilePath))
            {
                File.Delete(m_DownloadLocalFilePath);
            }

            m_DownloadLocalFilePath = m_DownloadLocalFilePath + ".temp";

            //如果通過這個(gè)函數(shù)調(diào)DownloadInnder,本地一定不會(huì)有這個(gè)文件了啊
            DownloadInner();
        }

        public void OnUpdate()
        {
            if (null == m_UnityWebRequest)
                return;

            //如果進(jìn)行重試了,判斷重試間隔
            if (m_CurrRetry > 0 && Time.time < m_PrevRetryTime + GameEntry.Download.RetryInterval)
                return;

            //大小=0,獲取web中的內(nèi)容大小數(shù)據(jù)
            if (m_TotalSize == 0)
                ulong.TryParse(m_UnityWebRequest.GetResponseHeader("Content-Length"),out m_TotalSize);

            //下載沒完成
            if (!m_UnityWebRequest.isDone)
            {
                //使用 unityWebRequest里面的下載字節(jié)大小
                if (m_CurrDownloadSize < m_UnityWebRequest.downloadedBytes)
                {
                    m_CurrDownloadSize = m_UnityWebRequest.downloadedBytes;

                    //通知更新
                    m_OnUpdate?.Invoke(m_CurrFileUrl,m_CurrDownloadSize,m_CurrDownloadSize/(float)m_TotalSize);
                }
                return;
            }

            //網(wǎng)絡(luò)錯(cuò)誤 || http 請(qǐng)求錯(cuò)誤
            if (m_UnityWebRequest.isNetworkError || m_UnityWebRequest.isHttpError)
            {
                ++m_CurrRetry;
                m_PrevRetryTime = Time.time;

                //大于了重試次數(shù)
                if (m_CurrRetry > GameEntry.Download.Retry)
                {
                    Reset();
                    GameEntry.Log(LogCategory.Resource, "下載完畢url=>{0} 失敗 當(dāng)前重試次數(shù){1}", m_UnityWebRequest.url, m_CurrRetry);

                    //嘗試重新下載
                    DownloadInner();
                    return;
                }
                GameEntry.Log(LogCategory.Resource, "下載完畢url=>{0} error=>{1}", m_UnityWebRequest.url, m_UnityWebRequest.error);
                Reset();
            }
            else
            {
                m_CurrDownloadSize = m_UnityWebRequest.downloadedBytes;

                //最后再更新一次
                m_OnUpdate?.Invoke(m_CurrFileUrl,m_CurrDownloadSize, m_CurrDownloadSize/(float)m_TotalSize);

                GameEntry.Log(LogCategory.Resource,"下載完畢url=>{0}",m_UnityWebRequest.url);
                
                Reset();

                //好像File里面沒有Rename操作,把a(bǔ)/b/c/xxx.ab.temp 移動(dòng)到a/b/c/xxx.ab
                //這好像是個(gè)改名的騷操作??!
                File.Move(m_DownloadLocalFilePath, m_DownloadLocalFilePath.Replace(".temp",""));

                m_DownloadLocalFilePath = null;

                if (PlayerPrefs.HasKey(m_CurrFileUrl))
                {
                    PlayerPrefs.DeleteKey(m_CurrFileUrl);
                }
                
                //這個(gè)文件 寫入本地版本文件信息
                GameEntry.Resource.ResManager.SaveVersion(m_CurrAssetBundleInfo);

                //回調(diào)OnComplete函數(shù)
                m_OnComplete?.Invoke(m_CurrFileUrl,this);
            }
        }

        //重置對(duì)象信息(我認(rèn)為每個(gè)可以被回收的類,都應(yīng)該有Reset)
        public void Reset()
        {
            if (null != m_UnityWebRequest)
            {
                //中斷連接|下載
                m_UnityWebRequest.Abort();

                //釋放 m_UnityWebRequest 內(nèi)部資源
                m_UnityWebRequest.Dispose();

                m_UnityWebRequest = null;
            }

            if (null != m_DownloadHandler)
            {
                //反注冊(cè)回調(diào)
                m_DownloadHandler.OnReceiveDataAction -= DownloadHandlerReceiveDataCallBack;
                m_DownloadHandler = null;
            }

            if (null != m_FileStream)
            {
                //關(guān)閉文件句柄(解除對(duì)該文件的占用,在操作系統(tǒng)里更改這個(gè)文件的狀態(tài))
                m_FileStream.Close();

                //清理 m_FileStream 內(nèi)部的資源
                m_FileStream.Dispose();
                m_FileStream = null;
            }

            m_PrevWriteSize = 0;
            m_TotalSize = 0;
            m_CurrDownloadSize = 0;
            m_CurrWaitFlushSize = 0;
        }

        public void Dispose()
        {
            Reset();
        }
    }

多文件下載器?DownloadMultiRoutine

????????多文件下載器內(nèi)部也是調(diào)用了單文件下載器,本質(zhì)上是對(duì)單文件下載器的封裝實(shí)現(xiàn)。解決單文件下載器在下載依賴文件或資源包時(shí)不好管理問題,所以分出來了一個(gè)多文件下載器。

- 函數(shù):下載中回調(diào) OnDownloadMultiUpdate

統(tǒng)計(jì)下載數(shù)據(jù),執(zhí)行下載中回調(diào)

- 函數(shù):下載完成回調(diào) OnDownloadMultiComplete

檢測(cè)繼續(xù)下載;執(zhí)行下載完成回調(diào)

+ 函數(shù):更新?OnUpdate

迭代執(zhí)行DownloadRoutine內(nèi)的OnUpdate

+ 函數(shù):開始下載多文件 BeginDownloadMulti?

下載數(shù)據(jù)記錄;分配DownloadRoutine下載;

+ 函數(shù):釋放對(duì)象 Dispose?

釋放對(duì)象內(nèi)部狀態(tài)?

DownloadMultiRoutine.cs 完整代碼

//多文件下載器
    public class DownloadMultiRoutine : IDisposable
    {
        //下載器鏈接
        private LinkedList<DownloadRoutine> m_ListDownloadRoutine;

        //需要下載的文件鏈表
        private LinkedList<string> m_ListNeedDownload;

        //多個(gè)文件下載中的回調(diào)函數(shù)
        private BaseAction<int, int, ulong, ulong> m_OnDownloadMultiUpdate;

        //多個(gè)文件下載完成的回調(diào)
        private BaseAction<DownloadMultiRoutine> m_OnDownloadMultiComplete;

        //多文件下載,需要下載的文件數(shù)量
        private int m_DownloadMultiNeedCount = 0;

        //多文件 當(dāng)前下載的數(shù)量
        private int m_DownloadMultiCurrCount = 0;

        //多文件 下載總共大小(單位:字節(jié))
        private ulong m_DownloadMultiTotalSize = 0;

        //多文件 當(dāng)前下載大?。▎挝唬鹤止?jié))
        private ulong m_DownloadMultiCurrSize = 0;

        //多文件 每個(gè)文件當(dāng)前下載的大?。▎挝唬鹤止?jié))
        private Dictionary<string, ulong> m_dicDownloadMultiCurrSize;

        public DownloadMultiRoutine()
        {
            m_ListDownloadRoutine = new LinkedList<DownloadRoutine>();
            m_ListNeedDownload = new LinkedList<string>();
            m_dicDownloadMultiCurrSize = new Dictionary<string, ulong>();
        }

        public void OnUpdate()
        {
            LinkedListNode<DownloadRoutine> iter = m_ListDownloadRoutine.First;
            for (; iter != null;)
            {
                iter.Value.OnUpdate();
                iter = iter.Next;
            }
        }


        #region 下載多個(gè)文件
        //多文件 下載中回調(diào)
        private void OnDownloadMultiUpdate(string url, ulong currDownloadedSize, float progress)
        {
            //緩存當(dāng)前文件下載的大小
            m_dicDownloadMultiCurrSize[url] = currDownloadedSize;

            ulong currSize = 0;
            IEnumerator<KeyValuePair<string, ulong>> iter = m_dicDownloadMultiCurrSize.GetEnumerator();
            for (; iter.MoveNext();)
            {
                currSize += iter.Current.Value;
            }

            //算出當(dāng)前下載的大小,保存
            m_DownloadMultiCurrSize = currSize;

            //安全保護(hù)
            if (m_DownloadMultiCurrSize > m_DownloadMultiTotalSize)
            {
                m_DownloadMultiCurrSize = m_DownloadMultiTotalSize;
            }

            //回調(diào),通知當(dāng)前的下載進(jìn)度
            m_OnDownloadMultiUpdate?.Invoke(m_DownloadMultiCurrCount, m_DownloadMultiNeedCount,
                                            m_DownloadMultiCurrSize, m_DownloadMultiTotalSize);
        }

        //單個(gè)文件下載完畢回調(diào)
        private void OnDownloadMultiComplete(string fileUrl, DownloadRoutine routine)
        {
            //檢查需要下載鏈表中 是否還有數(shù)據(jù),如果有繼續(xù)下載
            if (m_ListNeedDownload.Count > 0)
            {
                //讓下載器繼續(xù)工作,拿到頭部數(shù)據(jù)
                string url = m_ListNeedDownload.First.Value;
                m_ListNeedDownload.RemoveFirst();

                AssetBundleInfoEntity entity = GameEntry.Resource.ResManager.GetCDNAssetBundleInfo(url);
                routine.BeginDownload(url,entity,OnDownloadMultiUpdate, OnDownloadMultiComplete);
            }
            else
            {
                m_ListDownloadRoutine.Remove(routine);
                GameEntry.Pool.EnqueueClassObject(routine);
            }

            //當(dāng)前已下載數(shù)量+1
            m_DownloadMultiCurrCount++;

            m_OnDownloadMultiUpdate?.Invoke(m_DownloadMultiCurrCount, m_DownloadMultiNeedCount,
                                            m_DownloadMultiCurrSize,m_DownloadMultiTotalSize);


            //全部下載完成
            if (m_DownloadMultiCurrCount == m_DownloadMultiNeedCount)
            {
                //結(jié)束的時(shí)候 直接把當(dāng)前下載的大小設(shè)置為總大小
                m_DownloadMultiCurrSize = m_DownloadMultiTotalSize;

                m_OnDownloadMultiUpdate?.Invoke(m_DownloadMultiCurrCount, m_DownloadMultiNeedCount,
                                                m_DownloadMultiCurrSize, m_DownloadMultiTotalSize);

                m_OnDownloadMultiComplete?.Invoke(this);
            }
        }
            

        public void BeginDownloadMulti(LinkedList<string> lstUrl,
            BaseAction<int, int, ulong, ulong> onDownloadMultiUpdate = null,
            BaseAction<DownloadMultiRoutine> onDownloadComplete = null)
        {
            m_OnDownloadMultiUpdate = onDownloadMultiUpdate;
            m_OnDownloadMultiComplete = onDownloadComplete;

            //需要下載的文件列表&字典 清空
            m_ListNeedDownload.Clear();
            m_dicDownloadMultiCurrSize.Clear();

            //下載器記錄的下載數(shù)量和當(dāng)前下載數(shù)量重置
            m_DownloadMultiNeedCount = 0;
            m_DownloadMultiCurrCount = 0;

            //下載器記錄的下載大小數(shù)據(jù)重置
            m_DownloadMultiTotalSize = 0;
            m_DownloadMultiCurrSize = 0;

            //1.把需要下載的加入下載隊(duì)列
            for (LinkedListNode<string> iter = lstUrl.First; iter != null; iter = iter.Next)
            {
                string url = iter.Value;

                //多文件下載器加了限制,只有CDN上的資源才能下載,否則不允許下載
                AssetBundleInfoEntity entity = GameEntry.Resource.ResManager.GetCDNAssetBundleInfo(url);
                if (entity != null)
                {
                    //?這里等于不就行了 +=個(gè)毛???
                    m_DownloadMultiTotalSize += entity.Size;
                    m_DownloadMultiNeedCount++;
                    m_ListNeedDownload.AddLast(url);
                    m_dicDownloadMultiCurrSize[url] = 0;
                }
                else
                {
                    GameEntry.LogError("CDN站點(diǎn)無此資源=>" + url);
                }
            }

            //下載器數(shù)量,最大同時(shí)下載數(shù)(平衡下載速度和下載數(shù)量,之間做權(quán)衡)
            int routineCount = Math.Min(GameEntry.Download.DownloadRoutineCount, m_ListNeedDownload.Count) ;
            for (int i=0;i<routineCount;++i)
            {
                //類對(duì)象池取一個(gè)對(duì)象
                DownloadRoutine routine = GameEntry.Pool.DequeueClassObject<DownloadRoutine>();

                //取頭部的url,開始下載
                string url = m_ListNeedDownload.First.Value;
                m_ListNeedDownload.RemoveFirst();

                AssetBundleInfoEntity entity = GameEntry.Resource.ResManager.GetCDNAssetBundleInfo(url);
                routine.BeginDownload(url,entity, OnDownloadMultiUpdate, OnDownloadMultiComplete);
                m_ListDownloadRoutine.AddLast(routine);
            }
        }
        #endregion

        public void Dispose()
        {
            LinkedListNode<DownloadRoutine> iter=m_ListDownloadRoutine.First;
            for (; iter != null;)
            {
                iter.Value.Dispose();
                iter = iter.Next;
            }

            m_ListDownloadRoutine.Clear();
            m_ListNeedDownload.Clear();
            m_dicDownloadMultiCurrSize.Clear();
        }
    }

下載管理器?DownloadManager

? ? ? ? 下載管理器中對(duì),配置了下載數(shù)據(jù)的落地大小、重試次數(shù)、間隔等。管理器中存放了單下載器與多下載器的鏈表。

+ 函數(shù):管理器初始化 Init

?初始化配置

+ 函數(shù):下載單個(gè)文件 BeginDownloadSingle?

分配下載器,下載單個(gè)文件;下載完成后移除下載器;執(zhí)行完成回調(diào);

+ 函數(shù):下載文件列表?BeginDownloadMulti

分配下載器,下載多個(gè)文件;下載完成后移除下載器;執(zhí)行完成回調(diào);

+ 函數(shù):更新 OnUpdate

執(zhí)行單文件下載器和多文件下載器的OnUpdate

+ 函數(shù):清理對(duì)象狀態(tài) Dispose

調(diào)用單文件下載器和多文件下載器的Dispose文章來源地址http://www.zghlxwxcb.cn/news/detail-730080.html

DownloadManager.cs 完整代碼

 //下載管理器
    public class DownloadManager : ManagerBase, IDisposable
    {
        //寫入磁盤的緩存大?。▎挝唬篕 數(shù)據(jù)到達(dá)多少才寫入磁盤)
        public int FlushSize
        {
            get;
            private set;
        }

        //每個(gè)多文件下載器中的下載器最大數(shù)量
        public int DownloadRoutineCount
        {
            get;
            private set;
        }

        //連接失敗后 重試次數(shù)
        public int Retry
        {
            get;
            private set;
        }

        //重試間隔
        public int RetryInterval
        {
            get;
            private set;
        }

        //單文件下載器鏈表
        private LinkedList<DownloadRoutine> m_lstDownloadSingleRoutine;

        //多文件下載器連邊
        private LinkedList<DownloadMultiRoutine> m_lstDownloadMultiRoutine;

        public DownloadManager()
        {
            m_lstDownloadSingleRoutine = new LinkedList<DownloadRoutine>();
            m_lstDownloadMultiRoutine = new LinkedList<DownloadMultiRoutine>();
        }

        public override void Init()
        {
            //TODO:這里應(yīng)該讀取配置的
            Retry = 5;
            RetryInterval = 60;
            DownloadRoutineCount = 5;
            FlushSize = 2048;//2Mb
        }

        #region BeginDownloadSingle 下載單一文件
        /// <summary>
        //  下載單個(gè)文件
        /// </summary>
        /// <param name="url">文件鏈接</param>
        /// <param name="onUpdate">下載中的更新回調(diào)</param>
        /// <param name="onComplete">下載完成的回調(diào)</param>
        public void BeginDownloadSingle(string url, BaseAction<string, ulong, float> onUpdate = null, BaseAction<string> onComplete = null)
        {
            AssetBundleInfoEntity entity = GameEntry.Resource.ResManager.GetCDNAssetBundleInfo(url);
            if (null == entity)
            {
                GameEntry.LogError("資源包無效=>" + url);
                return;
            }

            DownloadRoutine routine = GameEntry.Pool.DequeueClassObject<DownloadRoutine>();
            routine.BeginDownload(url, entity, onUpdate, onComplete: (string fileUrl, DownloadRoutine r) =>
                {
                    //移除,歸還到對(duì)象池
                    m_lstDownloadSingleRoutine.Remove(r);
                    GameEntry.Pool.EnqueueClassObject(r);

                    onComplete?.Invoke(fileUrl);
                });

            m_lstDownloadSingleRoutine.AddLast(routine);
        }
        #endregion

        #region BeginDownloadMulti 下載多個(gè)文件
        /// <summary>
        /// 下載多個(gè)文件
        /// </summary>
        /// <param name="lstUrl">url鏈表</param>
        /// <param name="onUpdate">下載中更新回調(diào)</param>
        /// <param name="onComplete">下載完成回調(diào)</param>
        public void BeginDownloadMulti(LinkedList<string> lstUrl, BaseAction<int, int, ulong, ulong> onUpdate, BaseAction onComplete = null)
        {
            //從對(duì)象池里取一個(gè)多文件下載器
            DownloadMultiRoutine multiRoutine = GameEntry.Pool.DequeueClassObject<DownloadMultiRoutine>();

            multiRoutine.BeginDownloadMulti(lstUrl, onUpdate, onDownloadComplete: (DownloadMultiRoutine r) =>
              {
                  m_lstDownloadMultiRoutine.Remove(r);
                  GameEntry.Pool.EnqueueClassObject(r);
                  onComplete?.Invoke();
              });
        }
        #endregion

        //更新
        public void OnUpdate()
        {
            //遍歷更新單文件下載器
            LinkedListNode<DownloadRoutine> iterSingleRoutine = m_lstDownloadSingleRoutine.First;
            for (; iterSingleRoutine != null;)
            {
                iterSingleRoutine.Value.OnUpdate();
                iterSingleRoutine = iterSingleRoutine.Next;
            }
            
            //循環(huán)更新多文件下載器
            LinkedListNode<DownloadMultiRoutine> iterMultiRoutine = m_lstDownloadMultiRoutine.First;
            for (; iterMultiRoutine != null;)
            {
                iterMultiRoutine.Value.OnUpdate();
                iterMultiRoutine = iterMultiRoutine.Next;
            }
        }


        public void Dispose()
        {
            //清空單任務(wù)下載器鏈表
            LinkedListNode<DownloadRoutine> iter = m_lstDownloadSingleRoutine.First;
            for (; iter != null;)
            {
                iter.Value.Dispose();
                iter = iter.Next;
            }
            m_lstDownloadSingleRoutine.Clear();

            LinkedListNode<DownloadMultiRoutine> iterMultiRoutine = m_lstDownloadMultiRoutine.First;
            for (; iterMultiRoutine != null;)
            {
                iterMultiRoutine.Value.Dispose();
                iterMultiRoutine = iterMultiRoutine.Next;
            }

            //清空多任務(wù)下載器鏈表
            m_lstDownloadMultiRoutine.Clear();
        }
    }

到了這里,關(guān)于U3D客戶端框架之支持?jǐn)帱c(diǎn)續(xù)傳的文件下載器實(shí)現(xiàn)方案的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • U3D熱更新技術(shù)

    U3D熱更新技術(shù)

    @作者 : SYFStrive @博客首頁 : HomePage ??: 個(gè)人社區(qū)(歡迎大佬們加入) ??: 社區(qū)鏈接?? ???♀?: 創(chuàng)作不易轉(zhuǎn)發(fā)需經(jīng)作者同意?? ??: 程序員每天堅(jiān)持鍛煉?? ?? U3D熱更新技術(shù) (??) ??:開發(fā)者將測(cè)試好的代碼,發(fā)布到應(yīng)用商店的審核平臺(tái),平臺(tái)方會(huì)進(jìn)行穩(wěn)定性及性

    2024年02月02日
    瀏覽(25)
  • U3D通過按鈕點(diǎn)擊實(shí)現(xiàn)場(chǎng)景切換

    U3D通過按鈕點(diǎn)擊實(shí)現(xiàn)場(chǎng)景切換

    1.新建UI,選擇button選項(xiàng),新建button; ? 3.新建一個(gè)空對(duì)象,掛載一個(gè)scenechange c#腳本; 4.編寫腳本,1頭文件using UnityEngine.SceneMangement ? ? ? ? ? ? ? ? ? ?2public void change() { ? ? ? ? ? ? ? ? ? ? scenemanager.loadscene (1)? }//括號(hào)中的數(shù)字為第2步中場(chǎng)景后面的數(shù)字 ? ? ? ? ?

    2024年02月07日
    瀏覽(35)
  • 【Unity入門】1.創(chuàng)建第一個(gè)u3d項(xiàng)目

    【Unity入門】1.創(chuàng)建第一個(gè)u3d項(xiàng)目

    ? ? ? ? 大家好,我是Lampard~~ ?? ??歡迎來到Unity入門系列博客 ? ? Halo大家好久不見,最近半年比較懶惰,一直都比較少更新(不過擺爛確實(shí)挺開心哈哈哈哈哈)。最近項(xiàng)目要轉(zhuǎn)3D,引擎要從以前的cocos轉(zhuǎn)向unity,關(guān)注我的小伙伴可能知道,我以前開發(fā)的一直是cocos2d的內(nèi)容,

    2024年03月15日
    瀏覽(26)
  • 【U3D引擎】沒有切換中文選項(xiàng)&切換中文模式?

    【U3D引擎】沒有切換中文選項(xiàng)&切換中文模式?

    第一步,查看是否有勾選簡(jiǎn)體中文模塊 第二步,拉到底部,勾選簡(jiǎn)體中文,點(diǎn)擊繼續(xù) 第三步,勾選已閱讀同意后點(diǎn)擊安裝 第四步,等待下載安裝完成 過程中會(huì)自動(dòng)安裝VS軟件 如有下載失敗可重新下載 注:如果重復(fù)提示錯(cuò)誤也沒有沒有關(guān)系,直接略過就好, 第五步,隨便打

    2024年02月06日
    瀏覽(29)
  • AVProVideo??一、一款U3D視頻播放插件介紹

    AVProVideo??一、一款U3D視頻播放插件介紹

    ?? 商務(wù)合作:https://skode.cn/file/businesscard/wechat.jpg ?? 本文由 星河造夢(mèng)坊公司官方 原創(chuàng)! ?? 如果你有技術(shù)問題或項(xiàng)目開發(fā),都可以加上方的聯(lián)系方式,和我聊一聊你的故事?? 前段時(shí)間看到有人問: 橙哥,AVProVideo支持8K全景視頻嘛? 看來,好多人對(duì)這款插件的支持的功能

    2024年02月07日
    瀏覽(24)
  • 云備份客戶端——客戶端整體設(shè)計(jì)框架以及實(shí)用類工具實(shí)現(xiàn)

    客戶端要實(shí)現(xiàn)的功能和服務(wù)端相比相對(duì)簡(jiǎn)單,客戶端要實(shí)現(xiàn)的功能是 自動(dòng)對(duì)指定文件中的文件進(jìn)行備份,也就是定時(shí)對(duì)指定文件進(jìn)行掃描,根據(jù)文件信息判斷文件,符合要求(新文件或者被修改過的文件)進(jìn)行上傳 因此我們客戶端大概需要實(shí)現(xiàn)下面三個(gè)模塊 數(shù)據(jù)管理模塊:

    2024年02月09日
    瀏覽(28)
  • 使用U3D、pico開發(fā)VR(二)——添加手柄搖桿控制移動(dòng)

    使用U3D、pico開發(fā)VR(二)——添加手柄搖桿控制移動(dòng)

    1System: 2Move Speed:注意速度過小會(huì)導(dǎo)致看起來沒有移動(dòng) 3RightHandMoveAction(right loco move):個(gè)人采用右手柄實(shí)現(xiàn)移動(dòng) 1System: 2Turn?Speed:注意旋轉(zhuǎn)速度過小會(huì)導(dǎo)致看起來沒有移動(dòng) 3RightHandMoveAction:個(gè)人采用右手柄實(shí)現(xiàn)旋轉(zhuǎn) 至此,初步的移動(dòng)功能就實(shí)現(xiàn)了

    2024年02月08日
    瀏覽(30)
  • unity客戶端開源框架

    鏈接:https://github.com/yomunsam/TinaX/tree/master TinaX 主要實(shí)現(xiàn)了以下功能: Lua 語言支持 出于普遍的熱更新需求,TinaX原生提供了基于 Tencent/xlua 的Lua語言運(yùn)行環(huán)境,并為主要功能提供了Lua層面的API支持。 如果不需要Lua環(huán)境的話,也可以在項(xiàng)目中將Lua相關(guān)功能完全關(guān)閉,不會(huì)影響包

    2024年01月16日
    瀏覽(35)
  • RPC教程 2.支持并發(fā)與異步的客戶端

    對(duì)? net/rpc ?而言,一個(gè)函數(shù)需要能夠被遠(yuǎn)程調(diào)用,它必須滿足一定的條件,否則其會(huì)被忽略。 這些條件是: 方法的類型是可輸出的 (the method’s type is exported) 方法本身也是可輸出的 (the method is exported) 方法必須由兩個(gè)參數(shù),必須是輸出類型或者是內(nèi)建類型 (the method has tw

    2024年01月24日
    瀏覽(26)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包