简体   繁体   English

Part的构造函数被两次调用

[英]Constructor of Part is being called twice

Short story: 短篇故事:

I have a class that is being used as a Part in the e4xmi. 我有一个用作e4xmi中的零件的类。 This class has a constructor, which initializes a list, and methods that are bindings from a DS (declarative service on OSGi). 此类具有一个构造函数和一个方法,该构造函数用于初始化列表,该方法是DS(OSGi上的声明性服务)的绑定。 When the binding methods are called, this list should add or remove an item. 调用绑定方法时,此列表应添加或删除项目。

The first time the constructor is called (automatically by the e4, because it's a Part in the Application Model), the list is initialized. 第一次调用构造函数时(由于e4是应用程序模型的一部分,因此自动被e4调用),将初始化列表。 Ok, that's how it is supposed to work. 好的,这就是应该的方式。

After that, an item is added to the list (because the framework calls the DS binding method automatically). 之后,将一个项目添加到列表中(因为框架会自动调用DS绑定方法)。 But then, the constructor of Part is called again, initializing and clearing my list that had one item. 但是,然后再次调用Part的构造函数,初始化并清除我的只有一项的列表。

I don't know why the framework is calling the constructor twice. 我不知道为什么框架要两次调用构造函数。 What am I doing wrong? 我究竟做错了什么?

Long story: 很长的故事:

What I want to achieve: 我要实现的目标:

I've created a simple e4 RCP application for study purposes that would have a view capable of loading lots of widgets (clock, weather forecast, feeds, etc.) in runtime. 我出于研究目的创建了一个简单的e4 RCP应用程序,该应用程序具有一个能够在运行时加载许多小部件(时钟,天气预报,提要等)的视图。

What I think I should do to achieve that: 我认为我应该做些什么来实现这一目标:

In order to achieve that, I'm planning to have bundles that implements the same service (ie IWidget) and a view that looks up for that service and adds them in the layout. 为了实现这一点,我计划具有实现相同服务的捆绑软件(即IWidget)和一个查找该服务并将其添加到布局的视图。

What I currently have: 我目前所拥有的:

Currently I have 4 bundles: 目前,我有4个捆绑包:

  • Widget bundle, which has just a IWidget interface with a getName() method; Widget捆绑包,它只有一个具有getName()方法的IWidget接口;
  • ClockWidget bundle, an implementation of IWidget; ClockWidget捆绑包,是IWidget的实现;
  • MainViewPart, a Part that represents the main view. MainViewPart,代表主视图的Part。 It has methods to add/remove widgets whenever they are installed in the OSGi container. 它具有在OSGi容器中安装时添加/删除小部件的方法。 I'm doing this through DS (declarative services); 我正在通过DS(声明性服务)进行此操作;
  • Application, a project that contains an e4xmi file with a Part referencing the MainViewPart. 应用程序,一个包含e4xmi文件的项目,其中e4xmi文件的部件引用MainViewPart。

A simple class diagram can be found here to ease the explanation: 在这里可以找到一个简单的类图,以简化说明: 在此处输入图片说明

What my issue is: 我的问题是:

When I run the application, the MainViewPart constructor is being called twice, as you can see in the outputs: 运行应用程序时,MainViewPart构造函数被调用两次,如您在输出中所见:

*1. MainViewPart - Constructor
2. ClockWidget - Constructor
3. MainViewPart - Adding widget ClockWidget
*4. MainViewPart - Constructor
5. MainViewPart - @PostConstruct
6. MainViewPart - Removing widget ClockWidget

Notice that the MainViewPart constructor is being called in lines 1 and 4. I haven't seen anyone complaining about this in the web so probably I'm doing something wrong here. 请注意,在第1行和第4行中调用了MainViewPart构造函数。我没有看到任何人在网上抱怨此事,因此我可能在这里做错了什么。 This strange behaviour is a terrible limitation for me. 这种奇怪的行为对我来说是一个可怕的局限。 Actually I don't even know if this is a good approach to do what I'm trying to achieve. 实际上,我什至不知道这是否是实现我要实现的目标的好方法。

Any help would be appreciated. 任何帮助,将不胜感激。

Sources: 资料来源:

ClockWidget.java: ClockWidget.java:

package br.com.fernandopaz.rcp.test.widget.clock;

import br.com.fernandopaz.rcp.test.widget.IWidget;

public class ClockWidget implements IWidget {

    public ClockWidget() {
        System.out.println("ClockWidget - Constructor");
    }

    @Override
    public String getName() {
        return "ClockWidget";
    }
}

MainViewPart.java: MainViewPart.java:

package br.com.fernandopaz.rcp.test.part.mainview;

import javax.annotation.PostConstruct;
import org.eclipse.swt.widgets.Composite;
import br.com.fernandopaz.rcp.test.widget.IWidget;

public class MainViewPart {

    public MainViewPart() {
        System.out.println("MainViewPart - Constructor");
    }

    @PostConstruct
    public void postConstruct(Composite parent) {
        System.out.println("MainViewPart - @PostConstruct");
    }

    public void addWidget(IWidget widget) {
        System.out.println("MainViewPart - Adding widget " + widget.getName());
    }

    public void removeWidget(IWidget widget) {
        System.out.println("MainViewPart - Removing widget " + widget.getName());
    }
}

Application.e4xmi: Application.e4xmi:

<?xml version="1.0" encoding="UTF-8"?>
<application:Application xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:application="http://www.eclipse.org/ui/2010/UIModel/application" xmlns:basic="http://www.eclipse.org/ui/2010/UIModel/application/ui/basic" xmi:id="_T7vUMNx5EeOS5eqwaRWLag" elementId="org.eclipse.e4.ide.application" bindingContexts="_T7vUOdx5EeOS5eqwaRWLag">
  <children xsi:type="basic:TrimmedWindow" xmi:id="_T7vUMdx5EeOS5eqwaRWLag" label="br.com.fernandopaz.rcp.test" width="500" height="400">
    <children xsi:type="basic:PartSashContainer" xmi:id="_t7ieENx5EeOS5eqwaRWLag" elementId="br.com.fernandopaz.rcp.test.partsashcontainer.0">
      <children xsi:type="basic:Part" xmi:id="_uRJhsNx5EeOS5eqwaRWLag" elementId="br.com.fernandopaz.rcp.test.part.0" contributionURI="bundleclass://br.com.fernandopaz.rcp.test.part.mainview/br.com.fernandopaz.rcp.test.part.mainview.MainViewPart"/>
    </children>
  </children>
  <rootContext xmi:id="_T7vUOdx5EeOS5eqwaRWLag" elementId="org.eclipse.ui.contexts.dialogAndWindow" name="In Dialog and Windows">
    <children xmi:id="_T7vUOtx5EeOS5eqwaRWLag" elementId="org.eclipse.ui.contexts.window" name="In Windows"/>
    <children xmi:id="_T7vUO9x5EeOS5eqwaRWLag" elementId="org.eclipse.ui.contexts.dialog" name="In Dialogs"/>
  </rootContext>
  <addons xmi:id="_T7vUMtx5EeOS5eqwaRWLag" elementId="org.eclipse.e4.core.commands.service" contributionURI="bundleclass://org.eclipse.e4.core.commands/org.eclipse.e4.core.commands.CommandServiceAddon"/>
  <addons xmi:id="_T7vUM9x5EeOS5eqwaRWLag" elementId="org.eclipse.e4.ui.contexts.service" contributionURI="bundleclass://org.eclipse.e4.ui.services/org.eclipse.e4.ui.services.ContextServiceAddon"/>
  <addons xmi:id="_T7vUNNx5EeOS5eqwaRWLag" elementId="org.eclipse.e4.ui.bindings.service" contributionURI="bundleclass://org.eclipse.e4.ui.bindings/org.eclipse.e4.ui.bindings.BindingServiceAddon"/>
  <addons xmi:id="_T7vUNdx5EeOS5eqwaRWLag" elementId="org.eclipse.e4.ui.workbench.commands.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.CommandProcessingAddon"/>
  <addons xmi:id="_T7vUNtx5EeOS5eqwaRWLag" elementId="org.eclipse.e4.ui.workbench.handler.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.HandlerProcessingAddon"/>
  <addons xmi:id="_T7vUN9x5EeOS5eqwaRWLag" elementId="org.eclipse.e4.ui.workbench.contexts.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.ContextProcessingAddon"/>
  <addons xmi:id="_T7vUONx5EeOS5eqwaRWLag" elementId="org.eclipse.e4.ui.workbench.bindings.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench.swt/org.eclipse.e4.ui.workbench.swt.util.BindingProcessingAddon"/>
</application:Application>

Tom Schindl answered this question in the Eclipse Forums: http://www.eclipse.org/forums/index.php/mv/msg/755949/1371017/#msg_1371017 Tom Schindl在Eclipse论坛中回答了这个问题: http : //www.eclipse.org/forums/index.php/mv/msg/755949/1371017/#msg_1371017

There are 2 instances being construct because: 正在构造2个实例是因为:

  • OSGi automatically instantiates one MPart because I've declared it as a service using DS; OSGi自动实例化一个MPart,因为我已经使用DS将该MPart声明为服务。
  • e4 automatically instantiates another MPart because I've defined it as a Part in the Application Model (e4xmi). e4自动实例化另一个MPart,因为我已将其定义为应用程序模型(e4xmi)中的零件。

In order to avoid that, I considered two approaches: 为了避免这种情况,我考虑了两种方法:

  • Instead of using binding methods from the DS, I called a method in the @PostConstruct method that looks up for all IWidget s: 我没有使用DS中的绑定方法,而是在@PostConstruct方法中调用了一个查找所有IWidget的方法:

MainViewPart.java: MainViewPart.java:

private ArrayList<IWidget> widgets;

@PostConstruct
public void postConstruct(Composite parent) {
    lookupWidgets();
}

private void lookupWidgets() throws InvalidSyntaxException {
    widgets = new ArrayList<>();

    BundleContext context = FrameworkUtil.getBundle(this.getClass()).getBundleContext(); 
    Collection<ServiceReference<IWidget>> serviceReferences = context.getServiceReferences(IWidget.class, null);

    for (ServiceReference<IWidget> serviceReference : serviceReferences) {
        IWidget widget = (IWidget) context.getService(serviceReference);
        widgets.add(widget);
    }
}
  • Or create another bundle to store the widgets. 或创建另一个捆绑包来存储小部件。 The MPart will receive it in the @PostConstruct method through DI (Dependency Injection). MPart将通过DI(依赖注入)以@PostConstruct方法接收它。

WidgetList.java in the Widget List bundle: Widget List捆绑包中的WidgetList.java:

public class WidgetContainer {

    private ArrayList<IWidget> widgets;

    public WidgetContainer() {
        widgets = new ArrayList<>();
    }

    public void add(IWidget widget) {
        widgets.add(widget);
    }

    public void remove(IWidget widget) {
        widgets.remove(widget);
    }

    public ArrayList<IWidget> getWidgets() {
        return widgets;
    }
}

component.xml (DS) for the Widget List bundle: 窗口小部件列表捆绑包的component.xml(DS):

<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="WidgetList">
   <implementation class="br.com.fernandopaz.e4.test.widgetlist.WidgetList"/>
   <reference bind="add" cardinality="1..n" interface="br.com.fernandopaz.e4.test.widget.IWidget" name="IWidget" policy="dynamic" unbind="remove"/>
</scr:component>

MainViewPart.java in the Main View Part bundle: Main View Part捆绑包中的MainViewPart.java:

private ArrayList<IWidget> widgets;

@PostConstruct
public void postConstruct(Composite parent, WidgetList widgetList) {
    widgets = widgetList.getWidgets();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM