Unity學習—資源管理概覽

本文介紹了 Unity 常用四種默認路徑,以及 AssetDataBase、Resources、AssetBundle 和目前最新的 Addressable 四種資源管理方式

文中所有 API 均以版本 2019.3 為準

本文原地址:Unity學習—資源管理概覽

資源路徑

Application.dataPath

官方文檔

只讀,Editor 可讀寫

游戲數據相對路徑,即游戲安裝路徑,PC 上路徑會使用 '/' 分割文件夾

  • Unity Editor: <項目根路徑>/Assets
  • Mac player: <App 包路徑>/Contents
  • iOS player: <App 包路徑>/<AppName.app>/Data
  • Win/Linux player: <可執行數據文件夾路徑>
  • WebGL: player data 文件的 絕對 url 地址 (不包含具體文件名)
  • Android: 一般為 APK 路徑, 若使用 split binary build, 則為 OBB 路徑
  • Windows Store Apps: player data 文件夾的絕對地址

Application.persistentDataPath

官方文檔

可讀寫,用于持久化數據存儲,在 iOS 和 Android 平臺該路徑指向設備的公共路徑,該目錄不會隨 App 升級而刪除,但可被用戶直接刪除

persistentDataPath的路徑由Bundle Identifier生成的 GUID 組成,只要Bundle Identifier不變,路徑不變

iOS 會自動將 persistentDataPath 路徑下的文件備份到 iCloud

  • Windows Store Apps: %userprofile%\AppData\Local\Packages\<productname>\LocalState
  • iOS: /var/mobile/Containers/Data/Application/<guid>/Documents
  • Android: /storage/emulated/0/Android/data/<packagename>/files 該路徑由 android.content.Context.getExternalFilesDir 獲得,部分機型該路徑會指向 SD 卡
  • Mac: ~/Library/Application Support/<company name>/<product name> ,舊版本還可能為 ~/Library/Caches~/Library/Application Support/unity.company name.product name,Unity 會查詢并使用以上路徑中最早的路徑

Application.streamingAssetsPath

官方文檔 官方手冊

只讀,Editor 可讀寫

流數據存儲的相對路徑,該目錄下 Asset 在 Unity 編譯時不會被 Unity 打包,使其在運行時可直接通過路徑獲取,可將資源放入 Assets 目錄下任何名為 StreamingAssets文件夾

StreamingAssets中資源可使用 I/O 讀取,但 WebGL 和 Android 平臺下該路徑為 URL,不支持直接獲取,因此需使用 UnityWebRequest獲取。若其他平臺使用 UnityWebRequest 獲取,則需在路徑前加上"file://" ,如 "file://" + Application.streamingAssetsPath + "/file.mp4"

  • Unity Editor, Windows, Linux players, PS4, Xbox One, Switch : Application.dataPath + "/StreamingAssets"
  • Mac: Application.dataPath + "/Resources/Data/StreamingAssets"
  • iOS: Application.dataPath + "/Raw"
  • Android: "jar:file://" + Application.dataPath + "!/assets" (壓縮后的 APK/JAR 文件)

Application.temporaryCachePath

可讀寫,臨時數據和緩存路徑,應用更新或覆蓋安裝時不會被清除,手機空間不足時才可能會被系統清除

路徑示例

路徑 Editor Windows Mac OS iOS Android
Application.dataPath 項目路徑/Assets 安裝路徑/ProductName_Data /Applications/AppName.app/Contents /var/mobile/Containers/Data/Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/AppName.app/Data /data/app/package.name.apk
Application.persistentDataPath C:/Users/username/AppData/LocalLow/CompanyName/ProductName <br />或<br />/Users/username/Library/Application Support/CompanyName/ProductName C:\Users\username\AppData\LocalLow\CompanyName\ProductName /Users/username/Library/Application Support/CompanyName/AppName /var/mobile/Containers/Data/Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Documents /data/data/package.name/files
Application.streamingAssetsPath 項目路徑/Assets/StreamingAssets 安裝路徑/ProductName_Data/StreamingAssets /Applications/AppName.app/Contents/Resources/Data/StreamingAssets /var/containers/Bundle/Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/AppName.app/Data/Raw jar:file:///data/app/package.name.apk/!/assets
Application.temporaryCachePath C:/Users/username/AppData/Local/Temp/CompanyName/ProductName<br />或<br />/var/folders/xx/xxxxxxxxxxxxxx/X/CompanyName/ProductName C:\Users\username\AppData\Local\Temp\CompanyName\ProductName /var/folders/xx/xxxxxxxxxxxxxx/X/CompanyName/ProductName /var/mobile/Containers/Data/Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Library/Caches /data/data/package.name/cache

讀寫權限說明

https://blog.csdn.net/BillCYJ/article/details/99712313

資源加載

推薦官方教程

AssetDataBase

AssetDataBase 可在 Editor 環境下對項目 Asset 進行增刪改查等操作(可實現與 Unity 編輯器頂部工具欄 Assets 選項下基本相同的功能),使用方法可參考官方手冊 接口文檔

Resources

接口文檔

可在項目 Assets 目錄下任意位置創建Resources文件夾,打包時 Unity 會整合所有位于Resources文件夾的 Asset 及其依賴,并生成一個只讀的 resources.assets 資產文件,對于 Resources 目錄中在游戲中被直接引用的資產,則會被另外打包到 sharedassets0.assets

Resources 最佳實踐

官方的建議是不使用 Resources,有以下幾點原因:

  1. Resources 文件夾會導致內存管理困難
  2. 不適當使用 Resources 文件夾會加長應用啟動和編譯時間,Resources 文件夾越多,Asset 管理越困難
  3. Resources 系統降低項目針對指定平臺使用自定義內容的能力,并且無法實現增量更新(AssetBundle 是 Unity 針對不同設備提供特定內容的主要工具)

適合使用 Resources 的場景:

  1. 因其簡單快速的特性,適合用于快速原型和實驗開發,但當正式開發時應當減少使用
  2. 適合以下條件都滿足的狀況
    1. 該內容不會占用大量存儲資源
    2. 該內容在整個生命周期都需要
    3. 該內容幾乎不需要修改
    4. 該內容在不同平臺設備都一致

Resources 序列化

項目編譯時會將所有 Resources 目錄下 Asset 和 Object 合并到一個序列化的 resources.assets文件,該文件中還包含了類似于 AssetBundle 的元數據(metadata)和索引信息,該信息包含了由對象名稱轉化得到的 GUID 和 Local ID 的查找樹和對象位于序列化文件中的字節偏移量

對于大部分平臺,查找樹為時間復雜度為 O(n log(n)) 的平衡查找樹,隨著 Resources 中對象的增加,索引加載時間增長速度將超過線形增長速度

Resources 系統在 Splash 展示時初始化,該過程不可跳過,經觀察在低端設備上,10000 個 Asset 文件就會導致該過程長達數秒,哪怕很多對象在第一個場景沒用到也會被加載

接口 說明
FindObjectsOfTypeAll 獲取所有指定類型的對象
Load 加載 Resources 指定目錄下的 Asset
LoadAll 加載 Resources 指定目錄下的所有 Asset
LoadAsync 異步加載 Resources 指定目錄下的 Asset
UnloadAsset 將 asset 從內存釋放,重新加載 Asset 不會使之前的引用重新鏈接
UnloadUnusedAssets 釋放未使用的 Asset(包括僅在腳本堆棧使用,未在GameObject 使用)
void Start()
{
    //Load a text file (Assets/Resources/Text/textFile01.txt)
    var textFile = Resources.Load<TextAsset>("Text/textFile01");

    //Load text from a JSON file (Assets/Resources/Text/jsonFile01.json)
    var jsonTextFile = Resources.Load<TextAsset>("Text/jsonFile01");
    //Then use JsonUtility.FromJson<T>() to deserialize jsonTextFile into an object

    //Load a Texture (Assets/Resources/Textures/texture01.png)
    var texture = Resources.Load<Texture2D>("Textures/texture01");

    //Load a Sprite (Assets/Resources/Sprites/sprite01.png)
    var sprite = Resources.Load<Sprite>("Sprites/sprite01");

    //Load an AudioClip (Assets/Resources/Audio/audioClip01.mp3)
    var audioClip = Resources.Load<AudioClip>("Audio/audioClip01");
}

AssetBundle

官方手冊 接口文檔

AssetBundle 是外部資產的集合,可獨立于 Unity 構建過程外,是 Unity 更新非代碼內容的主要工具,經常置于服務器上供用戶終端動態獲取;AssetBundle 使開發者可以提交更小的應用包,最小化運行時內存壓力,使終端可以選擇性加載優化內容

該部分僅簡單介紹 AssetBundle,更多信息可見 Unity學習—AssetBundle

AssetBundle 構建

  1. 首先分配資產對象所在 AssetBundle,在 Project 窗口選中需要打包的 Asset,在 Inspect 窗口底部可見如下圖內容,底部 AssetBundle 后有兩個輸入選擇框,第一個為該資源所在 AssetBundle 名稱,第二個為 AssetBundle 變體名稱

    除此之外,Unity 還提供了 AssetImporter.assetBundleNameAssetImporter.assetBundleVariant等接口將資源分配到 AssetBundle

    image
  2. 然后即可構建 AssetBundle 了,使用BuildPipeline.BuildAssetBundles()即可構建 AssetBundle,其中可配置參數輸出路徑、構建選項、目標平臺

  3. 或者可以使用 Unity 官方提供的工具管理 AssetBundle AssetBundles-Browser 官方手冊

[MenuItem("Build Asset Bundles/Normal")]
static void BuildABsNone()
{
    BuildPipeline.BuildAssetBundles("Assets/MyAssetBuilds", BuildAssetBundleOptions.None, BuildTarget.StandaloneOSX);
}

AssetBundle 構建選項

BuildAssetBundleOptions
  • None
  • UncompressedAssetBundle:不壓縮
  • DisableWriteTypeTree:不包含類型信息
  • DeterministicAssetBundle:使用哈希值作為 Asset Id
  • ForceRebuildAssetBundle:強制重建
  • IgnoreTypeTreeChanges:增量構建檢查時忽略類型樹改動
  • AppendHashToAssetBundleName:AssetBundle 名稱后加哈希值
  • ChunkBasedCompression:使用 LZ4 壓縮
  • StrictMode:構建過程中任務錯誤即構建失敗
  • DryRunBuild:試運行
  • DisableLoadAssetByFileName:禁用名稱查找資源,可降低運行時內存提高加載效率
  • DisableLoadAssetByFileNameWithExtension:禁用帶后綴名的名稱查找資源,可降低運行時內存提高加載效率

AssetBundle 派發方式

根據實際情況選擇 AssetBundle 時隨項目打包,或后續通過網絡下載,一般移動平臺由于初始安裝大小和下載限制,會選擇安裝后下載,而主機和電腦則隨項目打包

隨項目打包有兩個主要原因:

  1. 減少項目構建時長,簡化迭代開發,針對無需單獨更新的 AssetBundle 可放在 StreamingAssets 目錄下
  2. 發布可更新的初始修正內容,用于節省用戶初始安裝后的時間和為后續修復做準備。但 StreamingAssets 不適用于該情況,若不考慮自定義下載和緩存系統,則可以使用 Unity 的緩存系統,從 StreamingAssets 下載初始緩存

一般推薦使用 UnityWebRequest下載 AssetBundle,若下載包為 LZMA 壓縮,則緩存的為未壓縮或使用 LZ4 重壓縮的內容,若緩存已滿,則 Unity 會刪除最近最少使用的 AssetBundle

Unity 內置的 AssetBundle 緩存系統用于緩存 UnityWebRequestAssetBundle.GetAssetBundle下載的包,緩存僅以名稱作為唯一標識。另外可通過重載方法可傳入版本號(開發者自己管理版本號),緩存系統會比對版本號,選擇匹配版本或下載新包

緩存系統可通過 Caching.expirationDelayCaching.maximumAvailableDiskSpace 修改最小未使用過期時間和最大緩存空間,當緩存文件在過期時間內沒被打開過即被刪除,或緩存空間不足,則優先刪除最近最少打開的緩存

IEnumerator GetText()
{
    using (UnityWebRequest uwr = UnityWebRequestAssetBundle.GetAssetBundle("http://www.my-server.com/mybundle"))
    {
        yield return uwr.SendWebRequest();

        if (uwr.isNetworkError || uwr.isHttpError)
        {
            Debug.Log(uwr.error);
        }
        else
        {
            // Get downloaded asset bundle
            AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(uwr);
        }
    }
}

AssetBundle 加載

有四種不同的 API 用于加載 AssetBundle,但每個 API 的行為隨壓縮算法和平臺而不同

  • AssetBundle.LoadFromMemoryAsync

    IEnumerator LoadFromMemoryAsync(string path)
    {
        AssetBundleCreateRequest createRequest = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes(path));
        yield return createRequest;
        AssetBundle bundle = createRequest.assetBundle;
        var prefab = bundle.LoadAsset<GameObject>("MyObject");
        Instantiate(prefab);
    }
    
  • AssetBundle.LoadFromFile

    該方法可高效地從硬盤加載未壓縮或 LZ4 壓縮的 Assetbundle,加載 LZMA 壓縮包時會先解壓再加載到內存

    public class LoadFromFileExample : MonoBehaviour {
        function Start() {
            var myLoadedAssetBundle 
                = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, "myassetBundle"));
            
            if (myLoadedAssetBundle == null) {
                Debug.Log("Failed to load AssetBundle!");
                return;
            }
            var prefab = myLoadedAssetBundle.LoadAsset.<GameObject>("MyObject");
            Instantiate(prefab);
        }
    }
    
  • WWW.LoadfromCacheOrDownload(5.6 及以前版本)

    舊方法,已拋棄

  • UnityWebRequestAssetBundle (5.3 及以后版本)

    先使用UnityWebRequest.GetAssetBundle創建請求,再將請求傳入DownloadHandlerAssetBundle.GetContent(UnityWebRequest),下載完成后可像AssetBundle.LoadFromFile 一樣,直接使用 assetBundle 對象

    該方法使開發者更靈活處理下載數據,選擇臨時存儲或長期緩存,避免不必要的內存使用。同時,由于是原生代碼,沒有托管堆棧擴展風險,DownloadHandler 也不會保留下載數據,進一步減少了內存開銷

    LZMA 壓縮包會在下載時解壓,并以 LZ4 重新壓縮緩存,可調用 Caching.CompressionEnabled 修改

    IEnumerator InstantiateObject()
    {
        string uri = "file:///" + Application.dataPath + "/AssetBundles/" + assetBundleName; 
        UnityEngine.Networking.UnityWebRequest request 
            = UnityEngine.Networking.UnityWebRequest.GetAssetBundle(uri, 0);
        yield return request.Send();
        AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);
        GameObject cube = bundle.LoadAsset<GameObject>("Cube");
        GameObject sprite = bundle.LoadAsset<GameObject>("Sprite");
        Instantiate(cube);
        Instantiate(sprite);
    }
    

官方推薦盡量使用 AssetBundle.LoadFromFile,該 API 在速度、磁盤使用和運行時內存使用方面都最高效;需要下載則使用 UnityWebRequest

AssetBundle Asset 加載

同步異步加載 Asset 一共有六種 API 可使用,同步方法一定比對應的異步方法快至少一幀

  • LoadAsset (LoadAssetAsync)
  • LoadAllAssets (LoadAllAssetsAsync)
  • LoadAssetWithSubAssets (LoadAssetWithSubAssetsAsync)

LoadAllAssets適合加載包中大部分或所有獨立 Unity 對象時使用,相較于多次重復調用另外兩種 API,LoadAllAssets速度要稍快一點。因此當 Asset 數量巨大且一次性需要加載的 Asset 少于 2/3 的時候,建議將 AssetBundle 拆分成多個小包體,再使用LoadAllAssets加載

LoadAssetWithSubAssets適合需要加載的對象內嵌了其他對象的情況,若加載對象均來自于一個 Asset 且包中有許多其他無關對象,則使用該 API

其他情況均用LoadAsset (LoadAssetAsync)

Unity 對象加載時在主線程執行,對象數據是在工作線程 worker thread,任何線程不敏感的操作都在工作線程執行

異步加載時會根據時間片限制每幀加載多個對象,自 Unity 5.3 后,對象加載就并行化了。多個對象在工作線程被反序列化、處理和集成,當對象加載完成,則觸發 Awake 回調

同步加載方法 AssetBundle.Load會暫停主線程知道加載完成,它們還將加載過程進行時間切片,以使對象集成所占用的幀時間不超過特定的毫秒數,該值可通過Application.backgroundLoadingPriority設定

  • ThreadPriority.High: 最大 50 毫秒每幀
  • ThreadPriority.Normal: 最大 10 毫秒每幀
  • ThreadPriority.BelowNormal: 最大 4 毫秒每幀
  • ThreadPriority.Low: 最大 2 毫秒每幀

在其他因素相同的情況下,異步加載方法的調用到加載對象可用之間最小有一幀延遲,導致異步加載方法比同步方法執行所需時間更長

AssetBundle 依賴

根據運行環境可以使用兩個不同的 API 自動追蹤 AssetBundle 之間的依賴。Editor 環境下,可使用AssetDatabase查詢依賴,使用AssetImporter訪問和修改 AssetBundle 的分配和依賴;運行時,可以通過基于 ScriptableObject 的 AssetBundleManifest API 加載在 AssetBundle 構建期間生成的依賴項信息

當一個對象所在的 AssetBundle 被加載時,該對象就被分配了一個唯一的有效實例 ID,因此 AssetBundle 的加載順序并不重要,重要的是在加載該對象本身之前,要優先把所有包含其依賴對象的 AssetBundle 加載好。

Unity 不會自動加載子 AssetBundle,具體可詳見手冊,例:

AssetBundle 1 中的 Material A 依賴于 AssetBundle 2 中的 Texture B,若要正常加載,與 AssetBundle 1 和 2 的加載順序無關,但一定要保證加載 Material A 時,AssetBundle 2 已加載

在構建 AssetBundle 時,Unity 創建一個包含每一個 AssetBundle 依賴信息的類型為 AssetBundleManifest 的序列化對象,該文件存在一個與其他 AssetBundle 在同一打包路徑下的單獨的 AssetBundle 中,且與父層文件夾名相同

有兩種 API 查詢依賴

  • AssetBundleManifest.GetAllDependencies 獲取 AssetBundle 的所有依賴層級
  • AssetBundleManifest.GetDirectDependencies 獲取 AssetBundle 直接依賴

因該 API 會生成字符串數組,所以應盡量少用,且避免性能高峰時使用

官方建議,大部分場合下,在進入性能需求高的場景前,盡可能多地加載對象,尤其對于移動平臺這種,訪問本地存儲慢,加載卸載對象引起內存流失會觸發垃圾回收的平臺

Asset 分包策略

  • 邏輯實體分包
  • 對象類型分包
  • 并發內容分包
邏輯實體分包

依據資源在項目功能塊的使用位置,如 UI、角色、環境和其他在生命周期中常出現的內容等分包

  • 將所有 UI 的紋理和布局數據分包
  • 將角色的模型和動畫數據分包
  • 將多場景共用的紋理和模型分包

該分包方式適用于制作 DLC,可以只下載單個實體而無需下載無變化的資源,其關鍵點在于需要開發者清楚了解每個打包的資源所要用到的時機和位置

對象類型分包

該方式適用于針對多平臺分包,例如音頻文件的壓縮設置在 Windows 和 Mac OS 平臺一樣,另外由于紋理壓縮格式和設置等改變頻率遠低于腳本和預設體,使用該分配方式可以使 AssetBundle 兼容更多的 Unity 版本

并發內容分包

并發內容分包可理解為以關卡為分組依據,將一個關卡內獨有的角色、紋理、音樂等需要在同一時機加載的內容分為一包

Tips
  • 將常更新與不常更新內容分開
  • 將需要同時加載的對象分為一組,如一個模型,其所需的材質和動畫分為一組
  • 若多個 AssetBundle 中的多個對象引用了其他 AssetBundle 中的單個 Asset,則將依賴項分離到單獨的包中以減少重復
  • 確保兩組完全不可能同時加載的對象不在用一包中,如低清和高清材質包
  • 若一個包中只有低于一半的對象被頻繁加載,可將其拆分
  • 將一些同時加載的小包(資源少于5到10個)合并
  • 若一個包中的對象僅是版本不同,則可以使用 AssetBundle 變體

Addressable

Addressable 系統為 Unity 新推出的資源管理系統,整合了 Unity 直接引用,Resources 和 AssetBundle 全部三種資源加載方式。通過可尋址資產的方式,便捷地實現了內容包的創建和部署。Addressable 系統使用異步加載的方式實現從任何位置加載任何依賴項,使得任何引用方式都更加便捷動態化

注意:需Unity 2018.3 及其以后版本

Addressable 優勢
  • 縮減迭代周期,無需修改代碼優化內容
  • 自動依賴管理,將請求內容的依賴項一同加載
  • 自動內存管理,對管理資源自動引用計數
  • 內容打包,負責構建和解析引用鏈,在將資源移動或重命名的情況下,依然可實現本地和遠端部署
  • 配置文件,可配置多個配置文件,實現快速切換
Addressable 概念

Addressable 由兩個包組成,Addressable Assets package(主要功能) 和 Scriptable Build Pipeline package(依賴項)

  • Address:資源的地址標記,用于運行時查詢
  • AddressableAssetData:在項目 Assets 目錄下用于存儲 Addressable 資源的文件目錄
  • Asset group:構建時處理的 Addressable 資產組
  • Asset group schema:數據構建時的配置
  • AssetReference:可根據需求延遲初始化的直接引用對象
  • Asynchronous loading:開發過程中無需更改代碼也可修改資產位置和依賴項
  • Build script:打包資產,將 Address 和 Resources 映射
  • Label:為運行時加載相似項目提供額外的 Addressable Asset 標志
Addressable 使用
Addressable 安裝
  1. 打開頂部工具欄 Window -> Package Manager,找到 Addressables,點擊安裝即可

    打開Pacakage Manager
    安裝 Addressable
  2. 安裝完成后 Addressable 的主要功能都可在頂部工具欄 Window -> Asset Management -> Addressables 中找到

    • Groups:Addressable 分組工具
    • Settings:Addressable 總體設置
    • Profiles:預設構建配置管理
    • EventViewer:監測引用計數工具
    • Analyze:用于分析打包情況,檢測重復等可自定義規則的分析工具
    • Hosting:模擬服務器
    打開 Addressables Group
  3. 打開Group,創建新的配置,項目 Assets 目錄下會自動創建一個 AddressableAssetData 目錄,無需直接改動該目錄

    image
image
Addressable Group 配置
  1. 在 Addressables Groups 窗口,右鍵或左上角 create 按鈕即可創建 Group
  2. 選中 Group,在 Inspector 中修改設置,Group 有三種配置項
    • Content Packing & Loading:打包的構建和加載路徑,以及其他打包相關設置
    • Content Update Restriction:包更新限制
    • Resources and Built In Scenes:是否包含 Resources 或構建的場景
  3. 添加 Asset 后,構建 Addressable Group
    • Addressables Groups 窗口,Build > New Build > Default Build Script
    • 或者使用 API AddressableAssetSettings.BuildPlayerContent()
Addressables Asset 配置和加載
  1. 添加 Addressable Asset

    • 將資源直接拖入 Addressables Groups 窗口下分組內即可

    • 或者在 Project 中選擇任何 Asset ,在 Inspector 下都可見名為 Addressable 的勾選框,勾選即可將該 Asset,可更改其 Addressable 名稱,此時該 Asset 就被添加到默認的 Addressables Group 中了

      image
  2. (可選) 更改資源名,為資源添加 Label

  3. 加載 Addressable Asset

    • Addressables.LoadAssetAsync<T>(string) 異步加載資源對象
    • Addressables.InstantiateAsync(string) 場景中創建對象
    • 或添加 AssetReference成員變量,在 Inspector 可選擇 AssetReference 引用的資源對象
    public class AddressablesExample : MonoBehaviour {
        GameObject myGameObject;
            ...
            Addressables.LoadAssetAsync<GameObject>("AssetAddress").Completed += OnLoadDone;
        }
    
        private void OnLoadDone(UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle<GameObject> obj)
        {
            // In a production environment, you should add exception handling to catch scenarios such as a null result.
            myGameObject = obj.Result;
        }
    }
    

參考

Unity讀取內部、外部資源詳解

Unity資源管理

The Addressable Asset System 正式版應用

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,461評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,538評論 3 417
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,423評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,991評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,761評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,207評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,268評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,419評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,959評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,653評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,901評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,678評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,978評論 2 374