为什么调用TreeViewer.refresh()不调用contentProvider的getChildren(Object)方法?

Why does calling TreeViewer.refresh() not call the contentProvider's getChildren(Object) method?

在其他地方,我已经看过 here and here,但我没有找到问题的答案。

一点背景知识:


根据 this 问题的信息:

If you have added or removed objects in the tree use

TreeViewer.refresh();

refresh()(没有参数)然后应该使用来自模型的新信息遍历并更新整个树。


通过在代码中设置断点,我发现在刷新过程中,框架在一个节点上多次调用hasChildren(),但是从未调用getChildren() .

假设Project当前是打开的,树中表示它的节点扩展了一些children。我关闭项目并触发资源更改事件。这会导致 refresh()。当被询问时,project 现在 returns 来自 hasChildren() 的错误,但 children 仍然存在于树中。

反之,如果项目关闭,节点没有children(没有展开箭头),打开项目会触发资源变化事件,refresh()是树, hasChildren() 中的项目节点 returns 为真,但从未调用 getChildren() 来找出这些 children 是什么。该节点仍然没有children,也没有扩展箭头。

当前,当添加新节点和删除旧节点时,模型会触发事件,树会侦听这些事件并在适当时在 TreeViewer 上调用 add(Object, Object)remove(Object),但模型仅检查当通过内容提供者的 getChildren() 方法请求它们时,查看它的 children 是否需要更改。

通过从 hasChildren() 调用 getChildren() 可以部分缓解问题,但这看起来很麻烦,而且根据我对 refresh() 工作原理的理解,应该没有必要。


为什么 TreeViewer 的 refresh() 方法不是 re-query 一个节点来查看它的 children 是什么?鉴于它不这样做,它意味着如何处理添加和删除 objects?

原来问题是 IElementComparer 传递给 TreeViewer.setComparer 的实现看起来像这样:

@Override
public boolean equals( final Object one, final Object two ) {
    if (one.getClass().equals( two.getClass() ) ) { <-- This is not always true...
        if ( one instanceof MyCustomNodeBaseClass) {
            return ((MyCustomNodeBaseClass) one).isEquivalentTo( (MyCustomNodeBaseClass) two);
        }
    }
    return false; <-- ...therefore this is the problem, as it wasn't expected to be reached
}

可以使用 class org.eclipse.ui.internal.ViewSite 的参数调用 IElementComparer.equals(Object, Object) 方法,并且也应该处理这些参数。

在无法识别参数的 class 的情况下,安静地 return false 是一个值得怀疑的举动,并且有问题的行可以替换为:

return ( one.equals( two ) ); <-- this will quietly handle unexpected classes better.

我最终通过跟随调试器进入 AbstractTreeViewer

updatePlus() 方法找到了这个