in stetho/src/main/java/com/facebook/stetho/inspector/elements/ShadowDocument.java [104:194]
public void setElementChildren(Object element, List<Object> children) {
// If we receive redundant information, then nothing needs to be done.
ElementInfo changesElementInfo = mElementToInfoChangesMap.get(element);
if (changesElementInfo != null &&
ListUtil.identityEquals(children, changesElementInfo.children)) {
return;
}
ElementInfo oldElementInfo = mElementToInfoMap.get(element);
if (changesElementInfo == null &&
oldElementInfo != null &&
ListUtil.identityEquals(children, oldElementInfo.children)) {
return;
}
ElementInfo newElementInfo;
if (changesElementInfo != null &&
oldElementInfo != null &&
oldElementInfo.parentElement == changesElementInfo.parentElement &&
ListUtil.identityEquals(children, oldElementInfo.children)) {
// setElementChildren() was already called for element with changes during this
// transaction, but now we're being told that the children should match the old view.
// So we should actually remove the change entry.
newElementInfo = mElementToInfoMap.get(element);
mElementToInfoChangesMap.remove(element);
} else {
Object parentElement = (changesElementInfo != null)
? changesElementInfo.parentElement
: (oldElementInfo != null)
? oldElementInfo.parentElement
: null;
newElementInfo = new ElementInfo(element, parentElement, children);
mElementToInfoChangesMap.put(element, newElementInfo);
}
// At this point, newElementInfo is either equal to oldElementInfo because we've reverted
// back to the same data that's in the old view of the tree, or it's a brand new object with
// brand new changes (it's different than both of oldElementInfo and changesElementInfo).
// Next, set the parentElement to null for child elements that have been removed from
// element's children. We must be careful not to set a parentElement to null if that child has
// already been moved to be the child of a different element. e.g.,
// setElementChildren(E, { A, B, C})
// ...
// setElementChildren(F, { A })
// setElementChildren(E, { B, C }) (don't mark A's parent as null in this case)
// notNewChildrenSet = (oldChildren + changesChildren) - newChildren
HashSet<Object> notNewChildrenSet = acquireNotNewChildrenHashSet();
if (oldElementInfo != null &&
oldElementInfo.children != newElementInfo.children) {
for (int i = 0, N = oldElementInfo.children.size(); i < N; ++i) {
final Object childElement = oldElementInfo.children.get(i);
notNewChildrenSet.add(childElement);
}
}
if (changesElementInfo != null &&
changesElementInfo.children != newElementInfo.children) {
for (int i = 0, N = changesElementInfo.children.size(); i < N; ++i) {
final Object childElement = changesElementInfo.children.get(i);
notNewChildrenSet.add(childElement);
}
}
for (int i = 0, N = newElementInfo.children.size(); i < N; ++i) {
final Object childElement = newElementInfo.children.get(i);
setElementParent(childElement, element);
notNewChildrenSet.remove(childElement);
}
for (Object childElement : notNewChildrenSet) {
final ElementInfo childChangesElementInfo = mElementToInfoChangesMap.get(childElement);
if (childChangesElementInfo != null &&
childChangesElementInfo.parentElement != element) {
// do nothing. this childElement was moved to be the child of another element.
continue;
}
final ElementInfo oldChangesElementInfo = mElementToInfoMap.get(childElement);
if (oldChangesElementInfo != null &&
oldChangesElementInfo.parentElement == element) {
setElementParent(childElement, null);
}
}
releaseNotNewChildrenHashSet(notNewChildrenSet);
}