OK, here I will summarize some code usage of Addressables. As we all know, the purpose of Addressables is to heat up, load and unload resources, which is equivalent to doing what our previous project should do for the management class AssetManager of AssetBundle resource package
1. The first is the hot change of resources. Most of the solutions check the resource updates in the login interface, and then download the updates locally. How to achieve this hot change in Addressables?
Check the Disable Catalog Update on Startup option first, which means that our Catalog will not be automatically updated when the application starts, but will be updated when the login interface is used to obtain the resources we need to download. Let's take a look at my code first:
public async Task CheckCatalogAsync(Action checkDoneCallback = null) { if(_isChecking) return; Debug.Log("check catalog begin"); _isChecking = true; if(!_catalogHandle.IsValid()) _catalogHandle = Addressables.CheckForCatalogUpdates(false); _catalogs = await _catalogHandle.Task; Debug.Log("catalogs:"+_catalogs.Count); if(_catalogs != null && _catalogs.Count > 0) { Debug.Log("Updatecatalogs begin"); List<object> keys = new List<object>(); var assets = await Addressables.UpdateCatalogs(_catalogs).Task; for(int i =0;i<assets.Count;i++) { keys.AddRange(assets[i].Keys); } Debug.Log("check download begin :" + keys.Count); await CheckDownloadAsync(keys,checkDoneCallback); } else { Addressables.Release(_catalogHandle); await CheckDoneToGameAsync(checkDoneCallback); } } private async Task CheckDownloadAsync(List<object> keys,Action checkDoneCallback = null) { downloadSize = await Addressables.GetDownloadSizeAsync(keys).Task; Debug.Log("downloadsize:"+downloadSize); if(downloadSize > 0) { string title = DataManager.GetText("Login_001"); string content = DataManager.GetText("Login_002", (Mathf.Ceil((float)downloadSize / (1024 * 1024))).ToString()); await UIManager.Instance.CreateDialogAsync(title,content, confirmCallback: async ()=>{ await UIManager.Instance.InstantiateDownloadProgressAsync(); await DownloadAsync(keys,checkDoneCallback); }, cancelCallback: ()=>{ _isChecking = false; }); } else { await CheckDoneToGameAsync(checkDoneCallback); } } private async Task DownloadAsync(List<object> keys,Action checkDoneCallback = null) { Debug.Log("dowload begin"); _downloadHandle = Addressables.DownloadDependenciesAsync(keys,Addressables.MergeMode.Union); while(!_downloadHandle.IsDone) { UIManager.Instance.ShowDownloadProgress(_downloadHandle.GetDownloadStatus().Percent); await Task.Delay(TimeSpan.FromSeconds(Time.deltaTime)); } Debug.Log("download finish"); if(_downloadHandle.Status == AsyncOperationStatus.Succeeded) { Debug.Log("download success!"); Addressables.Release(_catalogHandle); Addressables.Release(_downloadHandle); await CheckDoneToGameAsync(checkDoneCallback); } else { Debug.LogError("download failed! error:"+_downloadHandle.OperationException.ToString()); await UIManager.Instance.CreateDialogAsync("Login_001","Login_003", confirmCallback:async ()=>{ await DownloadAsync(keys,checkDoneCallback); }); } }
As shown in the code, I did three things: check the update of catalog - > check the size of resources to be downloaded and pop up the window - > start downloading after confirming the download. The first things to note are:
if(!_catalogHandle.IsValid())
_catalogHandle = Addressables.CheckForCatalogUpdates(false);
I made a cache here because some requirements are that clicking on the area outside the download pop-up window will hide or destroy the pop-up window, and then clicking on the login interface will pop up the download pop-up window. With this cache, there is no need to check the catalog. In addition, in the method of CheckForCatalogUpdate, it is necessary to fill in the parameter of false, because whether it is yield return or await, If you don't fill in false, the parameter will be automatically released after check, resulting in that you can't get relevant data in the future. You can see the code prompt through vs. if you have this autoreliasehandle parameter, you'd better weigh it in your mind. If you still need to operate some data in the future, yes, you must fill in false, Then manually unload and release it later
For example, I release it after the download is successful:
Then we will all encounter a problem. When I write these codes, it should not be solved, that is, breakpoint continuation. When I use Addressables, I find that once the catalog is updated and downloaded, even if I download some resources for the first time, kill the program and open it again, I will find that Addressables will be downloaded in the background, However, it will not follow the above code flow to pop up and continue downloading, so I also added the following code to solve this problem:
public async Task InitAsync() { _catalogPath = Application.persistentDataPath +"/com.unity.addressables"; if(Directory.Exists(_catalogPath)) { try { Directory.Delete(_catalogPath,true); Debug.Log("delete catalog cache done!"); } catch(Exception e) { Debug.LogError(e.ToString()); } } await Addressables.InitializeAsync().Task; _isInitDone = true; Debug.Log("AssetManager init done"); }
Yes, we only need to delete the folder where the catalog is located before the Addressables initialization, so it can continue to transmit from the breakpoint. That's why in the first chapter, we need to set the Cache Initialization Settings to our persistentDataPath. If Addressables has a more elegant solution now, please let me know in the comment area, Thank you first ~
2. Loading and unloading of resources
There are only two methods used to load resources: LoadAssetAsync and instantiatasync. Sometimes LoadAssetsAsync is used. This method can add a callback function, which is very easy to use. For example:
private async Task LoadTextsAsync(List<string> paths) { var handle = Addressables.LoadAssetsAsync<TextAsset>(paths,ParseText,Addressables.MergeMode.Union,true); await handle.Task; Addressables.Release(handle); }
In short, it will execute ParseText every time it loads a path resource in paths. I'm sure you'll understand what scenarios it applies to right away
Unloading of resources: there are only two officially given by Unity, ReleaseInstance and Release. The first one is commonly used for GameObject from instantiaeasync, and Release is commonly used for unloading resources from Load. However, I tried to unload the handle of instantiaeasync with Release, and the handle is OK, Sometimes some dependent resources are loaded and cannot be unloaded from memory through Release. At this time, call resources Unloadunusedassets may solve your troubles
There are also some advanced uses: for example, Labels in the group allows you to classify resources, which is very easy to use. For example, you may arrange different picture resolutions according to the performance of the mobile phone, so you can load them through Labels into three categories: low definition, general definition and high definition
Finally, the official documents of Addressables are attached: Addressables | Addressables | 1.19.18