Gluon 重用视图并优先使用受保护的事件挂钩进行填充

Gluon reusing view and populating prefeably using a protected event hook

在 Gluon 中注册一个视图工厂,Gluon 在需要时使用它来创建视图。

addViewFactory(HOME_VIEW, () -> new LoginView());
addViewFactory(SelectView.class.getSimpleName(), () -> new SelectView());

然后您可以使用以下方式切换视图:

MobileApplication.getInstance().switchView(SelectView.class.getSimpleName());

如果您在 SelectView 上并且想返回,您可以使用这个:

MobileApplication.getInstance().switchToPreviousView();

现在问题来了:在转到 SelectView 后,回到上一个,然后再回到 SelectView,Gluon 决定不创建新视图,而是重用现有视图。这并不是真正的问题,甚至可能是一件好事,它只是意味着初始化代码需要拆分为 "createView" 和 "populateView" 方法。在 onShowing 事件中调用 populateView 方法。一切顺利。

我的问题是我似乎无法为此覆盖 'onShowing()' 方法,但需要使用 setOnShowing 方法实际注册。这似乎不仅偏离了标准的做事方式(例如重写 updateAppBar 方法),而且还意味着声明一个事件挂钩供内部使用,实际上更适合外部使用(外部侦听器)。

我是不是做错了什么?

出于性能原因,Gluon 的视图被缓存。每当您添加一个视图时,您都会提供一个供应商,它将在需要该视图时调用。此时,视图将被添加到缓存中,下次您需要相同的视图时,将从该缓存中检索它。只有当它没有找到时,例如在内存限制下它可以被删除,它会从供应商那里重新创建。

因此,正如您所说,只为视图编写一次代码(您的 "createView")是有意义的,该代码在该视图的整个生命周期中保持不变,并且调用的可变代码也是如此每次显示视图(您的 "populateView"),但从缓存中获取,而不调用其构造函数。

对于有多个视图的项目,使用 MVP 方法、FXML 和 Gluon Glisten-Afterburner 框架会更方便。

在这种情况下,视图创建并注册一次,可以使用presenter通过initialize()定义视图。

如果您检查任何使用此方法的示例(例如 Notes 应用程序),您将看到:

  • 注册视图(Notes 视图是一个 AppView,它创建一个从 FXMLView 扩展的 GluonView):

    public static final AppView NOTES_VIEW = view("Notes", NotesPresenter.class, MaterialDesignIcon.HOME, SHOW_IN_DRAWER, HOME_VIEW, SKIP_VIEW_STACK);
    
  • 创建演示者:

    public class NotesPresenter extends GluonPresenter<NotesApp>  {
    
        @FXML private View notes;
    
        public void initialize() {
             // one time only code
             ...
             // code required each time the view is displayed
        }
    
    }
    

现在您可以使用视图的某些 properties,例如 showingProperty()onShowingProperty()onShownProperty() 添加无法从外部删除或覆盖的侦听器查看:

public void initialize() {
    notes.showingProperty().addListener((obs, oldValue, newValue) -> {
        if (newValue) {
            // update appBar 
            AppBar appBar = getApp().getAppBar();
            ...
        }
    });
}

同样可以应用于常规视图,当然:

View view = new View() {

    private final Label label;
    {
        label = new Label("some text");

        showingProperty().addListener((obs, ov, nv) -> {
            if (nv) {
                // update view
                label.setText("new text");
            }
        });
        onShownProperty().addListener((obs, ov, nv) -> {
            // add something when view is fully shown
        });
        onHiddenProperty().addListener((obs, ov, nv) -> {
            // remove something when view is hidden
        });
    }

    @Override
    protected void updateAppBar(AppBar appBar) {
        ...
    }

};