First, if you use Addressables that reference ScriptableObjects (SO), those SOs need to be Addressables as well. Then, you just need to ensure that everyone is using the same AssetReference and that the Addressable has been loaded before it is used.
There are a few solutions to achieve this:
Expose the AssetReference instead of the SO in your scripts, and then use a static class to load it. This class will also cache the loaded instances in a dictionary.
To see how to use this, here’s an example:
There is an EnemySpawner that loads the enemy prefab as an Addressable. Additionally, each enemy prefab has a script, Enemy.cs, which exposes a reference to an AssetReference of the SO event. The only difference when using SO events as Addressables is that we need to expose an AssetReference (instead of the SO), make the SO event an Addressable, and ensure we load it (using the static class) before using it.
Load the AssetReference in one script, then pass it as a dependency to all other scripts that need a reference to it. This breaks the independence of SOs, but it works.
Create a "manager" or an SO database that will load all your AssetReferences. Any class that needs a specific SO will have to interact with this manager to get the loaded Addressable.
Create a loading scene that will load all Addressables, then load other scenes as Addressables. I found this solution here.
Of course, it would be great to be able to use the EventListeners and the Bindings with Addressables, and I am planning to try to support that in the future. In the meantime, load and use the addressables SO by code and do not use the EventListeners or Bindings in Addressable loaded prefabs or scenes.