Skip to content

Commit 53b44e2

Browse files
authored
Merge pull request #14 from IvanMurzak/feature/automatic-texture-release
Automatic texture memory release
2 parents da8aec8 + 5469cc5 commit 53b44e2

22 files changed

+786
-130
lines changed

Assets/Samples.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Assets/Samples/CacheSample.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using Extensions.Unity.ImageLoader;
2+
using UnityEngine;
3+
4+
static class CacheSample
5+
{
6+
static string url = "";
7+
static Sprite sprite;
8+
9+
static void ChangeDiskCacheFolder()
10+
{
11+
ImageLoader.settings.diskSaveLocation = Application.persistentDataPath + "/myCustomFolder";
12+
}
13+
static void OverrideCache()
14+
{
15+
// Override Memory cache for specific image
16+
ImageLoader.SaveToMemoryCache(url, sprite);
17+
18+
// Take from Memory cache for specific image if exists
19+
ImageLoader.LoadFromMemoryCache(url);
20+
}
21+
static void DoesCacheContainImage()
22+
{
23+
// Check if any cache contains specific image
24+
ImageLoader.CacheContains(url);
25+
26+
// Check if Memory cache contains specific image
27+
ImageLoader.MemoryCacheContains(url);
28+
29+
// Check if Memory cache contains specific image
30+
ImageLoader.DiskCacheContains(url);
31+
}
32+
static void ClearImage()
33+
{
34+
// Clear memory Memory and Disk cache
35+
ImageLoader.ClearCache();
36+
37+
// Clear only Memory cache for all images
38+
ImageLoader.ClearMemoryCache();
39+
40+
// Clear only Memory cache for specific image
41+
ImageLoader.ClearMemoryCache(url);
42+
43+
// Clear only Disk cache for all images
44+
ImageLoader.ClearDiskCache();
45+
46+
// Clear only Disk cache for specific image
47+
ImageLoader.ClearDiskCache(url);
48+
}
49+
}

Assets/Samples/CacheSample.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using Extensions.Unity.ImageLoader;
2+
using Cysharp.Threading.Tasks;
3+
using UnityEngine;
4+
using UnityEngine.UI;
5+
6+
public class ImageLoaderSample : MonoBehaviour
7+
{
8+
[SerializeField] string imageURL;
9+
[SerializeField] Image image;
10+
11+
async void Start()
12+
{
13+
// Loading sprite from web, cached for quick load next time
14+
image.sprite = await ImageLoader.LoadSprite(imageURL);
15+
16+
// Same loading with auto set to image
17+
await ImageLoader.SetSprite(imageURL, image);
18+
}
19+
}

Assets/Samples/ImageLoaderSample.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using Extensions.Unity.ImageLoader;
2+
using Cysharp.Threading.Tasks;
3+
using UnityEngine;
4+
using UnityEngine.UI;
5+
6+
public class ImageLoaderSample2 : MonoBehaviour
7+
{
8+
[SerializeField] string imageURL;
9+
[SerializeField] Image image1;
10+
[SerializeField] Image image2;
11+
12+
void Start()
13+
{
14+
// Loading with auto set to image
15+
ImageLoader.SetSprite(imageURL, image1, image2).Forget();
16+
}
17+
}

Assets/Samples/ImageLoaderSample2.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Assets/_PackageRoot/README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,18 @@ public class ImageLoaderSample : MonoBehaviour
6060
}
6161
```
6262

63+
# Texture Memory Management
64+
65+
ImageLoader can manager memory usage of loaded textures. To use it need to call `ImageLoader.LoadSpriteRef` instead of `ImageLoader.LoadSprite`. It will return `Reference<Sprite>` object which contains `Sprite` and `Url` objects. When `Reference<Sprite>` object is not needed anymore, call `Dispose` method to release memory, or just don't save the reference on it. It is `IDisposable` and it will clean itself automatically. Each new instance of `Reference<Sprite>` increments reference counter of the texture. When the last reference is disposed, the texture will be unloaded from memory. Also the all related References will be automatically disposed if you call `ImageLoader.ClearMemoryCache` or `ImageLoader.ClearCache`.
66+
67+
``` C#
68+
// Load sprite image and get reference to it
69+
await ImageLoader.LoadSpriteRef(imageURL);
70+
71+
// Take from Memory cache reference for specific image if exists
72+
ImageLoader.LoadFromMemoryCacheRef(url);
73+
```
74+
6375
# Cache
6476

6577
Cache system based on the two layers. The first layer is **memory cache**, second is **disk cache**. Each layer could be enabled or disabled. Could be used without caching at all. By default both layers are enabled.
@@ -68,7 +80,7 @@ Cache system based on the two layers. The first layer is **memory cache**, secon
6880

6981
- `ImageLoader.settings.useMemoryCache = true;` default value is `true`
7082
- `ImageLoader.settings.useDiskCache = true;` default value is `true`
71-
83+
7284
Change disk cache folder:
7385

7486
``` C#
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
using System;
2+
using UnityEngine;
3+
using UnityEngine.Networking;
4+
using Cysharp.Threading.Tasks;
5+
6+
namespace Extensions.Unity.ImageLoader
7+
{
8+
public static partial class ImageLoader
9+
{
10+
/// <summary>
11+
/// Load image from web or local path and return it as Sprite
12+
/// </summary>
13+
/// <param name="url">URL to the picture, web or local</param>
14+
/// <param name="textureFormat">TextureFormat for the Texture2D creation</param>
15+
/// <param name="ignoreImageNotFoundError">Ignore error if the image was not found by specified url</param>
16+
/// <returns>Returns sprite asynchronously </returns>
17+
public static UniTask<Sprite> LoadSprite(string url, TextureFormat textureFormat = TextureFormat.ARGB32, bool ignoreImageNotFoundError = false)
18+
=> LoadSprite(url, new Vector2(0.5f, 0.5f), textureFormat, ignoreImageNotFoundError);
19+
20+
/// <summary>
21+
/// Load image from web or local path and return it as Sprite
22+
/// </summary>
23+
/// <param name="url">URL to the picture, web or local</param>
24+
/// <param name="pivot">Pivot of created Sprite</param>
25+
/// <param name="textureFormat">TextureFormat for the Texture2D creation</param>
26+
/// <param name="ignoreImageNotFoundError">Ignore error if the image was not found by specified url</param>
27+
/// <returns>Returns sprite asynchronously </returns>
28+
public static async UniTask<Sprite> LoadSprite(string url, Vector2 pivot, TextureFormat textureFormat = TextureFormat.ARGB32, bool ignoreImageNotFoundError = false)
29+
{
30+
if (string.IsNullOrEmpty(url))
31+
{
32+
if (settings.debugLevel <= DebugLevel.Error)
33+
Debug.LogError($"[ImageLoader] Empty url. Image could not be loaded!");
34+
return null;
35+
}
36+
37+
if (MemoryCacheContains(url))
38+
{
39+
var sprite = LoadFromMemoryCache(url);
40+
if (sprite != null)
41+
return sprite;
42+
}
43+
44+
if (IsLoading(url))
45+
{
46+
if (settings.debugLevel <= DebugLevel.Log)
47+
Debug.Log($"[ImageLoader] Waiting while another task is loading the sprite url={url}");
48+
await UniTask.WaitWhile(() => IsLoading(url));
49+
return await LoadSprite(url, textureFormat, ignoreImageNotFoundError);
50+
}
51+
52+
AddLoading(url);
53+
54+
if (settings.debugLevel <= DebugLevel.Log)
55+
Debug.Log($"[ImageLoader] Loading new Sprite into memory url={url}");
56+
try
57+
{
58+
var cachedImage = await LoadDiskAsync(url);
59+
if (cachedImage != null && cachedImage.Length > 0)
60+
{
61+
await UniTask.SwitchToMainThread();
62+
var texture = new Texture2D(2, 2, textureFormat, true);
63+
if (texture.LoadImage(cachedImage))
64+
{
65+
var sprite = ToSprite(texture, pivot);
66+
if (sprite != null)
67+
SaveToMemoryCache(url, sprite, replace: true);
68+
69+
RemoveLoading(url);
70+
return sprite;
71+
}
72+
}
73+
}
74+
catch (Exception e)
75+
{
76+
if (settings.debugLevel <= DebugLevel.Exception)
77+
Debug.LogException(e);
78+
}
79+
80+
UnityWebRequest request = null;
81+
var finished = false;
82+
UniTask.Post(async () =>
83+
{
84+
try
85+
{
86+
request = UnityWebRequestTexture.GetTexture(url);
87+
await request.SendWebRequest();
88+
}
89+
catch (Exception e)
90+
{
91+
if (!ignoreImageNotFoundError)
92+
if (settings.debugLevel <= DebugLevel.Exception)
93+
Debug.LogException(e);
94+
}
95+
finally
96+
{
97+
finished = true;
98+
}
99+
});
100+
await UniTask.WaitUntil(() => finished);
101+
102+
RemoveLoading(url);
103+
104+
#if UNITY_2020_1_OR_NEWER
105+
var isError = request.result != UnityWebRequest.Result.Success;
106+
#else
107+
var isError = request.isNetworkError || request.isHttpError;
108+
#endif
109+
110+
if (isError)
111+
{
112+
if (settings.debugLevel <= DebugLevel.Error)
113+
#if UNITY_2020_1_OR_NEWER
114+
Debug.LogError($"[ImageLoader] {request.result} {request.error}: url={url}");
115+
#else
116+
Debug.LogError($"[ImageLoader] {request.error}: url={url}");
117+
#endif
118+
return null;
119+
}
120+
else
121+
{
122+
await SaveDiskAsync(url, request.downloadHandler.data);
123+
var sprite = ToSprite(((DownloadHandlerTexture)request.downloadHandler).texture);
124+
SaveToMemoryCache(url, sprite, replace: true);
125+
return sprite;
126+
}
127+
}
128+
}
129+
}

Assets/_PackageRoot/Runtime/ImageLoader.LoadSprite.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)