Failure to comply to these instructions will lead to your Unity Developer License being revoked for life.
Seriously, it’s been bothering me for many years that AssetDatabase.Refresh() is being indiscriminately used everywhere everytime anything even remotely related to the asset pipeline is being called … just because it can’t hurt, right?
Well yes, it can! Read on … and learn why you’ve been calling it way too often!
The AssetDatabase.Refresh() FAQ
Everything You Always Wanted to Know About Refresh()*
(*But Didn’t Bother to Ask)
What is AssetDatabase.Refresh() - really?
It is ONLY needed when asset changes were made BYPASSING the AssetDatabase entirely!
By calling Refresh() in such cases, Unity will check for such changes and integrate them into the AssetDatabase, triggering Asset Importers where necessary.
If, however, all changes were made via AssetDatabase methods to begin with, the AssetDatabase already knows about these changes! It really needn’t check the entirety of the Assets file system tree for changes nor call Resource.UnloadUnusedAssets() internally afterwards.
When to call Refresh()?
- CALL: after using System.IO methods, eg Directory.CreateDirectory(), File.WriteAllText(), etc operating within the /Assets tree (except for /Assets/StreamingAssets)
- CALL: after running an external program or script modifying /Assets contents without Unity editor losing focus at the same time (Editor regaining focus triggers an auto-refresh)
- CALL: after using a code snippet/framework that wasn’t written specifically for Unity and which modifies contents in the /Assets tree
What happens when you didn’t call Refresh() when you should have?
The common issues of what happens in such a case are fairly obvious once you’re aware of them:
- A directory or file you created / deleted / moved / renamed is not correctly listed in the Project explorer view (missing or still there)
- Calls to the AssetDatabase (such as Find, Load, Import) with the new asset path fail or return null
- A file whose contents were modified does not trigger the asset importer, which results in these changes not being reflected in the Editor - Note: in such cases you would simply call Import(), not Refresh()!
There may be other reasons for Auto-Refresh not working as expected. In such cases investigate the following:
- Preferences => Asset Pipeline => Auto Refresh disabled?
- DisallowAutoRefresh() not followed by and equal number of AllowAutoRefresh() calls?
- StartAssetEditing() not followed by an equal number of StopAssetEditing() calls?
- Exception raised in the latter two cases where these method pairs were not properly enclosed within a try{Disallow/Start} finally{Allow/Stop} block?
When NOT to call Refresh()?
- DON’T CALL: after modifying assets solely via calls to AssetDatabase (Create/Copy/Delete/Extract/Import/Load/Move/Rename/Save)
- DON’T CALL: after modifying asset contents solely via calls to AssetDatabase (AddObject/ClearLabels/SetLabels/SetMainObject/…)
- DON’T CALL: after calls to Start/StopAssetEditing and Disallow/AllowAutoRefresh (unless changes were made bypassing the AssetDatabase in between)
- DON’T CALL: there’s probably more … feel free to post your example use case for analysis
Why not just call Refresh() anyway - it can’t hurt, right?
- Possible loss of data! Assets referenced only by scripts are unloaded. If such an asset was modified but not flagged as “dirty” those changes are lost after Refresh()! We’ve probably all experienced these at some point but never attributed them to Refresh().
- It’s a code smell, and is a bad habit all around the Unity community. It’s needlessly consuming time and resources to call Refresh() indiscriminately. It runs an asset garbage collection cycle, unloading unused assets, which may slow down the editor (worst case: a continuous unload/reload cycle).
Thanks for reading!
Your Unity license should be save … for now. I’ll be watching.