Not setStateInformation itself but APVTS::replaceState (and ValueTree’s copy assignment operator, which replaceState calls).
I can’t verify that, at least for elements other than root -after replaceState, my ValueTree listeners are not called. Maybe it works for properties added manually to the root element, I didn’t test that.
I think the only reasonable “solution” is to make the reconnections in setStateInformation itself, after replaceState. It’s safer than relying on your valueTreeRedirected being called after APVTS’s. But even better is not using APVTS::state to connect with the UI -that’s what ParameterAttachment and its relatives are for.
I actually don’t use replaceState, or assigment of ValueTrees, also because it’s not undoable. copyPropertiesAndChildrenFrom is undoable, but it breaks connections for children. Both copyPropertiesAndChildrenFrom and copyPropertiesFrom are problematic for versioning. If you’ve added a parameter in v1.2, and you load a host chunk saved with v1.1, the new parameter gets removed. So I load my states manually, with something like
void MyAudioProcessor::setStateFromXml (const juce::XmlElement& xml, bool msgThread)
{
if (msgThread) undoManager.beginNewTransaction();
forEachXmlChildElementWithTagName (xml, x, "PARAM")
{
auto& id{ x->getStringAttribute ("id") };
auto value{ x->getDoubleAttribute ("value", -65536.) };
if (id.isNotEmpty() && value != -65536.)
{
if (auto param{ apvts.getParameter (id) })
{
auto normalised{ param->convertTo0to1 (float (value)) };
if (normalised != param->getValue())
{
if (msgThread) param->beginChangeGesture();
param->setValueNotifyingHost (normalised);
if (msgThread) param->endChangeGesture();
}
}
}
}
}
I use separate ValueTrees for non automatable parameters to avoid messing with APVTS. If you never replace them (as in tree = anotherTree), connections shouldn’t break. In getStateInformation I prepend them like
if (auto xml{ apvts.copyState().createXml() })
{
xml->prependChildElement (anotherTree.createXml().release());
copyXmlToBinary (*xml, destData);
}
In setStateInformation, because it can be called from any thread, I defer the changes for non automatable parameters to the message thread (basically save the xml pointer and check it from a Timer callback), then I apply them manually. It’s a bit of a hassle, but it’s what I need.