0

バンドルのヒップを持つアプリケーションを作成しています。それらのいくつかはインターフェースであり、いくつかはそれらのインターフェースの実装です。サービスを提供および使用するために宣言型サービス (DS) を使用しています。つまり、各バンドルには、提供/参照しているサービスを記述する component.xml があります。

ClockWidget現在、 3 つのインターフェイスを実装するという名前のクラスがあります (添付の図を参照)。実装されたサービスごとに、このサービスを参照する特定のクラスがあります。たとえば、Timeoutクラスには、サービスを実装する人を受け取る bind メソッドがありTimeoutListenerます。 ここに画像の説明を入力

問題は、ClockWidgetクラスのコンストラクターが 3 回呼び出されていることです。明らかに、それを他のバンドルで使用されているサービスの数と関連付けました。

問題は、複数のサービスを実装するバンドルを処理するための適切なアプローチ/プラクティスは何ですか? つまり、このバンドルをアプリケーション内で複製したくありません。この男を参照している 3 つのクラスで同じインスタンスを使用したいと思います。マニフェストで singleton プロパティを有効にしようとしましたが、何も変わりませんでした。

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>

なにか提案を?

4

2 に答える 2

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();
        }
    }
}

ご覧のとおり、メソッドは OSGi にインストールされlookupActivityListenersているすべての を検索し、ActivityListenerそれらを配列リストに追加します。行にコメントを付けましたがActivityListener activityListener = (ActivityListener) context.getService(serviceReference);、コンストラクターは一度呼び出されました。

lookupActivityListeners();そのため、呼び出しをコンストラクターではなく別の場所に変更する必要がありました。今、すべてが順調です。しかし、なぜそれが問題の原因になるのかはまだわかりません。

とにかく答えてくれてありがとう。

于 2014-05-30T00:04:52.480 に答える