UFL5-6——AB包资源管理器的异步加载修改
UFL5-6——AB包资源管理器的异步加载修改
管理器代码继承自:UH1L4——AB包资源管理器
重新按照ABMgr中的规则进行AB包打包
ABMgr异步加载修改主要目标
将ABMgr中的异步加载方法彻底异步化,让其中的依赖包加载、资源包加载、资源加载都变为异步加载
注意:主包可以保留同步加载
需要考虑的主要问题
-
某个AB包当正在异步加载时又进行重复加载,遇到这种情况时,我们需要避免重复加载报错
因此我们不应再次加载,而是等待之前的异步加载结束后直接使用首先将同步加载AB包的方法
LoadAB
进行拆分,将加载主包的逻辑提取出来,新声明一个LoadMainAB
去实现1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34private void LoadMainAB()
{
//加载主包
if (mainAB == null)
{
mainAB = AssetBundle.LoadFromFile(PathUrl + MainABName);
manifest = mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
}
}
public void LoadAB(string abName)
{
LoadMainAB();
//获取依赖包相关信息
AssetBundle ab;
//加载主包中的关键配置文件 获取依赖包
string[] strs = manifest.GetAllDependencies(abName);
//加载依赖包
for (int i = 0; i < strs.Length; i++)
{
//判断包是否加载过
if (!abDic.ContainsKey(strs[i]))
{
ab = AssetBundle.LoadFromFile(PathUrl + strs[i]);
abDic.Add(strs[i], ab);
}
}
//加载目标包
if (!abDic.ContainsKey(abName))
{
ab = AssetBundle.LoadFromFile(PathUrl + abName);
abDic.Add(abName, ab);
}
}然后将原来协程内的异步加载协程方法内调用
LoadAB
的部分都替换掉,转为实现新的逻辑-
同步加载主包
-
获取依赖包
-
循环加载依赖包
-
如果字典内不存在记录,说明没有加载过
- 加载前就往字典内添加记录,值传入
null
,然后异步加载AB包,直到加载完毕后才向字典内对应的记录赋值,关联加载出来的AB包
- 加载前就往字典内添加记录,值传入
-
字典内存在记录,说明AB包正在异步加载或者加载已经结束了
- 如果字典内对应的记录值为空,说明正在加载,此时就循环挂起一帧协程,直到发现记录内关联了AB包
-
-
加载目标包
-
如果字典内不存在记录,说明没有加载过
- 加载前就往字典内添加记录,值传入
null
,然后异步加载AB包,直到加载完毕后才向字典内对应的记录赋值,关联加载出来的AB包
- 加载前就往字典内添加记录,值传入
-
字典内存在记录,说明AB包正在异步加载或者加载已经结束了
- 如果字典内对应的记录值为空,说明正在加载,此时就循环挂起一帧协程,直到发现记录内关联了AB包
-
-
从目标包内加载异步资源,将加载出来的资源传入到回调函数内执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56private IEnumerator LoadResCoroutine<T>(string abName, string resName, UnityAction<T> callBack) where T : Object
{
//加载AB包
LoadMainAB();
//加载主包中的关键配置文件 获取依赖包
string[] strs = manifest.GetAllDependencies(abName);
//加载依赖包
for (int i = 0; i < strs.Length; i++)
{
//判断包是否加载过
if (!abDic.ContainsKey(strs[i]))
{
//一开始异步加载就记录,如果此时的记录的AB包为空,说明该AB包正在异步加载
abDic.Add(strs[i], null);
AssetBundleCreateRequest req = AssetBundle.LoadFromFileAsync(PathUrl + strs[i]);
yield return req;
//异步加载结束后再替换以前的null,此时记录的AB包不为null,证明加载结束了
abDic[strs[i]] = req.assetBundle;
}
//字典存在记录,说明AB包正在异步加载或者加载已经结束了
else
{
//如果字典中记录的消息是null,则证明正在加载中,这时就需要等待加载结束
while (abDic[strs[i]] == null)
{
//只要发现正在加载中,就不停的等待一帧,下一帧再进行判断
yield return 0;
}
}
}
//加载目标包
if (!abDic.ContainsKey(abName))
{
//一开始异步加载就记录,如果此时的记录的AB包为空,说明该AB包正在异步加载
abDic.Add(abName, null);
AssetBundleCreateRequest req = AssetBundle.LoadFromFileAsync(PathUrl + abName);
yield return req;
//异步加载结束后再替换以前的null,此时记录的AB包不为null,证明加载结束了
abDic[abName] = req.assetBundle;
}
//字典存在记录,说明AB包正在异步加载或者加载已经结束了
else
{
//如果字典中记录的消息是null,则证明正在加载中,这时就需要等待加载结束
while (abDic[abName] == null)
{
//只要发现正在加载中,就不停的等待一帧,下一帧再进行判断
yield return 0;
}
}
AssetBundleRequest abr = abDic[abName].LoadAssetAsync<T>(resName);
yield return abr;
//异步加载结束后,通过委托,传递给外部,来使用
callBack(abr.asset as T);
}其他的异步加载协程的重载也替换掉
LoadAB
,换成新的异步加载AB包的逻辑1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111private IEnumerator LoadResCoroutine(string abName, string resName, UnityAction<Object> callBack)
{
//加载AB包
LoadMainAB();
//加载主包中的关键配置文件 获取依赖包
string[] strs = manifest.GetAllDependencies(abName);
//加载依赖包
for (int i = 0; i < strs.Length; i++)
{
//判断包是否加载过
if (!abDic.ContainsKey(strs[i]))
{
//一开始异步加载就记录,如果此时的记录的AB包为空,说明该AB包正在异步加载
abDic.Add(strs[i], null);
AssetBundleCreateRequest req = AssetBundle.LoadFromFileAsync(PathUrl + strs[i]);
yield return req;
//异步加载结束后再替换以前的null,此时记录的AB包不为null,证明加载结束了
abDic[strs[i]] = req.assetBundle;
}
//字典存在记录,说明AB包正在异步加载或者加载已经结束了
else
{
//如果字典中记录的消息是null,则证明正在加载中,这时就需要等待加载结束
while (abDic[strs[i]] == null)
{
//只要发现正在加载中,就不停的等待一帧,下一帧再进行判断
yield return 0;
}
}
}
//加载目标包
if (!abDic.ContainsKey(abName))
{
//一开始异步加载就记录,如果此时的记录的AB包为空,说明该AB包正在异步加载
abDic.Add(abName, null);
AssetBundleCreateRequest req = AssetBundle.LoadFromFileAsync(PathUrl + abName);
yield return req;
//异步加载结束后再替换以前的null,此时记录的AB包不为null,证明加载结束了
abDic[abName] = req.assetBundle;
}
//字典存在记录,说明AB包正在异步加载或者加载已经结束了
else
{
//如果字典中记录的消息是null,则证明正在加载中,这时就需要等待加载结束
while (abDic[abName] == null)
{
//只要发现正在加载中,就不停的等待一帧,下一帧再进行判断
yield return 0;
}
}
AssetBundleRequest abr = abDic[abName].LoadAssetAsync(resName);
yield return abr;
//异步加载结束后,通过委托,传递给外部,来使用
callBack(abr.asset);
}
private IEnumerator LoadResCoroutine(string abName, string resName, System.Type type, UnityAction<Object> callBack)
{
//加载AB包
LoadMainAB();
//加载主包中的关键配置文件 获取依赖包
string[] strs = manifest.GetAllDependencies(abName);
//加载依赖包
for (int i = 0; i < strs.Length; i++)
{
//判断包是否加载过
if (!abDic.ContainsKey(strs[i]))
{
//一开始异步加载就记录,如果此时的记录的AB包为空,说明该AB包正在异步加载
abDic.Add(strs[i], null);
AssetBundleCreateRequest req = AssetBundle.LoadFromFileAsync(PathUrl + strs[i]);
yield return req;
//异步加载结束后再替换以前的null,此时记录的AB包不为null,证明加载结束了
abDic[strs[i]] = req.assetBundle;
}
//字典存在记录,说明AB包正在异步加载或者加载已经结束了
else
{
//如果字典中记录的消息是null,则证明正在加载中,这时就需要等待加载结束
while (abDic[strs[i]] == null)
{
//只要发现正在加载中,就不停的等待一帧,下一帧再进行判断
yield return 0;
}
}
}
//加载目标包
if (!abDic.ContainsKey(abName))
{
//一开始异步加载就记录,如果此时的记录的AB包为空,说明该AB包正在异步加载
abDic.Add(abName, null);
AssetBundleCreateRequest req = AssetBundle.LoadFromFileAsync(PathUrl + abName);
yield return req;
//异步加载结束后再替换以前的null,此时记录的AB包不为null,证明加载结束了
abDic[abName] = req.assetBundle;
}
//字典存在记录,说明AB包正在异步加载或者加载已经结束了
else
{
//如果字典中记录的消息是null,则证明正在加载中,这时就需要等待加载结束
while (abDic[abName] == null)
{
//只要发现正在加载中,就不停的等待一帧,下一帧再进行判断
yield return 0;
}
}
AssetBundleRequest abr = abDic[abName].LoadAssetAsync(resName, type);
yield return abr;
//异步加载结束后,通过委托,传递给外部,来使用
callBack(abr.asset);
} -
-
正在加载某个AB包时
-
卸载AB包:如果正在加载中,不允许卸载
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17//单个包卸载
public void UnLoad(string abName, UnityAction<bool> callBackResult)
{
if (abDic.ContainsKey(abName))
{
if (abDic[abName] == null)
{
//如果发现正在异步加载,则不允许卸载,向回调函数传入false
callBackResult?.Invoke(false);
return;
}
abDic[abName].Unload(false);
abDic.Remove(abName);
//卸载成功,向回调函数传入true
callBackResult?.Invoke(true);
}
} -
清空AB包:停止所有协同程序,在清理AB包
1
2
3
4
5
6
7
8
9
10
11//所有包的卸载
public void ClearAB()
{
//由于AB包都是异步加载,同时停止所有的异步加载协程
StopAllCoroutines();
AssetBundle.UnloadAllAssetBundles(false);
abDic.Clear();
//卸载主包,卸载依赖文件
mainAB = null;
manifest = null;
}
-
使用示例
两次异步加载同一包下的同一资源
1 | public class Main : MonoBehaviour |
输出:
具体代码
1 | using System.Collections; |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 文KRIFE齐的博客!