我正在创建一个包含臀部的应用程序。其中一些是接口,一些是这些接口的实现。我使用声明性服务(DS)来提供和使用服务,这意味着每个bundle都有一个component.xml,用于描述我提供/引用的服务。
目前我有一个名为ClockWidget
的类,它实现了3个接口(如附图所示)。对于每个实现的服务,我有一个引用此服务的特定类。例如,Timeout
类具有绑定方法,可以接收实现TimeoutListener
服务的任何人。
问题是ClockWidget
类的构造函数被调用了三次。显然,我将其与其他捆绑包使用的服务数量联系起来。
问题是:为了处理实现多个服务的捆绑包,有什么好方法/做法?我的意思是,我不希望在应用程序中复制此捆绑包。我想在引用这个人的三个类中使用相同的实例。我试图在清单中启用单例属性,但没有任何改变。
ClockWidget.class
:
public class ClockWidget implements Widget, TimeoutListener, DummyInterface {
public ClockWidget() {
System.out.println("ClockWidget constructor.");
}
@Override
public String getWidgetName() {
return "Clock widget";
}
@Override
public void onTimeout() {
System.out.println("Timeout!");
}
@Override
public void dummyMethod() {
// Does nothing.
}
}
其组件定义ClockWidget.xml
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="test.e4.ClockWidget">
<implementation class="test.e4.history.ClockWidget"/>
<service>
<provide interface="test.e4.widget.Widget"/>
<provide interface="test.e4.timeoutlistener.TimeoutListener"/>
<provide interface="test.e4.dummyinterface.DummyInterface"/>
</service>
</scr:component>
使用ClockWidget
提供的服务的类。在这种情况下,Timeout
类:
public class Timeout {
private ArrayList<TimeoutListener> listeners;
public Timeout() {
listeners = new ArrayList<>();
startTimeoutTimer();
}
public void startTimeoutTimer() {
long timeoutInMs = 60 * 1000;
Timer timeoutTimer = new Timer();
timeoutTimer.schedule(new TimerTask() {
@Override
public void run() {
timeout();
}
}, timeoutInMs);
}
// Bind method from DS
public void addListener(TimeoutListener listener) {
listeners.add(listener);
}
// Unbind method from DS
public void removeListener(TimeoutListener listener) {
listeners.remove(listener);
}
public void timeout() {
for (TimeoutListener listener : listeners) {
listener.onTimeout();
}
}
}
超时组件说明:
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="test.e4.Timeout">
<implementation class="test.e4.Timeout"/>
<reference bind="addListener" cardinality="0..n" interface="test.e4.timeoutlistener.TimeoutListener" name="TimeoutListener" policy="dynamic" unbind="removeListener"/>
</scr:component>
有什么建议吗?
答案 0 :(得分:2)
ClockWidget是一个在3个服务名称下注册的DS组件吗?或者每个在一个服务名称下注册的3个DS组件。如果是后者,那么是的,ClockWidget将为每个服务实例化一次,因为这是所有DS都知道的。如果是前者,则ClockWidget只应实例化一次,因为它是在3个服务名下提供的单个服务。
答案 1 :(得分:0)
ClockWidget
类有另一个在构造函数中调用的方法。我不知道这可能会导致这个问题。以下是完整ClockWidget.class
的外观:
public class ClockWidget extends Widget implements TimeoutListener, DummyInterface {
private ArrayList<ActivityListeners> activityListeners;
public ClockWidget() {
super();
System.out.println("ClockWidget constructor.");
lookupActivityListeners();
}
@Override
public String getWidgetName() {
return "Clock widget";
}
@Override
public void onTimeout() {
System.out.println("Timeout!");
}
@Override
public void dummyMethod() {
// Does nothing.
}
private void lookupActivityListeners() {
activityListeners = new ArrayList<>();
try {
BundleContext context = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
Collection<ServiceReference<ActivityListener>> serviceReferences = context.getServiceReferences(ActivityListener.class, null);
for (ServiceReference<ActivityListener> serviceReference : serviceReferences) {
ActivityListener activityListener = (ActivityListener) context.getService(serviceReference);
if (activityListener != null) {
activityListeners.add(activityListener);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
如您所见,方法lookupActivityListeners
搜索OSGi中安装的所有ActivityListener
,并将它们添加到数组列表中。我已对ActivityListener activityListener = (ActivityListener) context.getService(serviceReference);
行进行了评论,并且构造函数被调用一次。
所以我不得不将lookupActivityListeners();
调用更改为另一个地方而不是构造函数。现在一切都很好。但是,我仍然不知道为什么会成为问题的根源。
无论如何,谢谢你的答案。