2017-01-09 47 views
0

我相信我已經看到這個問題的變種,但沒有「確定的答案」。在下面的代碼中,我明白SomeEventManager持有對someImplClassTwo.myEventListenerA和someImplClassTwo.myEventListenerB的引用,並且這不允許someImplClassTwo被垃圾收集,並且這導致第二次生成的輸出someEventManager.notifyListeners()是調用。但是,我真的希望SomeImplClass的用戶不必知道在實現中有涉及的監聽器,並且這些監聽器需要手動取消註冊(即SomeImplClass.releaseListeners())釋放SomeImplClass對象。有沒有一種「乾淨」的方式來自動取消在Java中註冊監聽器?

是否有乾淨/可接受的方式來做到這一點?

p.s.我已經玩過finalize(),只是爲了好玩,並且確認GC在這種情況下甚至沒有嘗試過,對於任何一個SomeImplClass的實例。所以,這似乎是一個不可能的解決方案。

測試驅動

public class TestDriver { 
    public static void main(String[] args) { 
     SomeEventManager someEventManager = SomeEventManager.getInstance(); 
     SomeImplClass someImplClassOne = new SomeImplClass("One"); 
     SomeImplClass someImplClassTwo = new SomeImplClass("Two"); 

     someEventManager.notifyListeners(); 

     someImplClassOne.releaseListeners(); 
     someImplClassOne = null; 
     someImplClassTwo = null; 
     try { 
      Thread.sleep(1000); 
     } catch(InterruptedException e) { 
     } 
     someEventManager.notifyListeners(); 
    } 
} 

事件接口

public interface SomeEventListener { 
    public void handleSomeEvent(); 
} 

事件管理器

import java.util.ArrayList; 
import java.util.List; 

public class SomeEventManager { 
    private static SomeEventManager  eventManager = null; 
    private  List<SomeEventListener> listeners = null; 

    private SomeEventManager() { 
     listeners = new ArrayList<SomeEventListener>(); 
    } 

    public static SomeEventManager getInstance() { 
     if (eventManager == null) { 
      eventManager = new SomeEventManager(); 
     } 
     return eventManager; 
    } 

    public void addListener(SomeEventListener listener) { 
     if (!listeners.contains(listener)) { 
      listeners.add(listener); 
     } 
    } 

    public void removeListener(SomeEventListener listener) { 
     listeners.remove(listener); 
    } 

    public void notifyListeners() { 
     for(SomeEventListener listener : listeners) { 
      listener.handleSomeEvent(); 
     } 
    } 
} 

事件監聽器實現

public class SomeImplClass { 
    private InnerEventListener myEventListenerA = null; 
    private InnerEventListener myEventListenerB = null; 
    private String    id    = null; 

    public SomeImplClass(String id) { 
     this.id = id; 
     myEventListenerA = new InnerEventListener(id + "_A"); 
     myEventListenerB = new InnerEventListener(id + "_B"); 
    } 

    public void releaseListeners() { 
     myEventListenerA.unregisterListener(); 
     myEventListenerB.unregisterListener(); 
    } 

    private class InnerEventListener implements SomeEventListener { 
     private SomeEventManager someEventManager = null; 
     private String   id    = null; 

     public InnerEventListener(String id) { 
      someEventManager = SomeEventManager.getInstance(); 
      this.id   = id; 
      registerListener(); 
     } 

     public void registerListener() { 
      someEventManager.addListener(this); 
     } 

     public void unregisterListener() { 
      someEventManager.removeListener(this); 
     } 

     public void handleSomeEvent() { 
      System.out.println("InnerEventListener->" + id); 
     } 
    } 
} 
+0

請參閱['WeakHashMap'](http://stackoverflow.com/questions/5511279/what-is-a-weakhashmap-and-when-to-use-it) –

回答

1

我們使用的解決方案是讓偵聽器自動註銷自己,如果它被調用並且它正在更新的事物已被收集。

它看起來有點像這樣:

private static class InnerEventListener implements SomeEventListener { 
    private final WeakReference<ThingToUpdate> thingRef; 

    public InnerEventListener(ThingToUpdate thing) { 
     thingRef = new WeakReference<>(thing); 
    } 

    @Override 
    public void handleSomeEvent(SomeEvent event) { 
     ThingToUpdate thing = thingRef.get(); 
     if (thing != null) { 
      thing.updateSomehow(); 
     } else { 
      ((SomeEventedThing) event.getSource()) 
       .removeSomeEventListener(this); 
     } 
    } 
} 

//... 

SomeEventedThing eventedThing; 
ThingToUpdate thingToUpdate; 

//... 

eventedThing.addListener(new InnerEventListener(thingToUpdate)); 

我不會說這是一個完美的解決方案,因爲聽衆支左右,直到它得到一個事件,它仍然一定程度上取決於垃圾收集。我們一直試圖在可能的情況下用明確的刪除來替換它,通常在GUI組件上使用addNotify/removeNotify。

+0

我正在採取類似的路線.. 。目前。您的方法假定ThingToUpdate的生命週期不會超出偵聽器的範圍,因此特定於該方案。 我的方法將偵聽器本身視爲弱引用(也是實現特定的?),但適用於我的需要。但是,我不能讓聽衆成爲一個內部類,因爲外部類擁有強大的參照,而內部的內在參照(假設強大?)到外部......防止被垃圾收集。 如果Java對內部類的引用使用了一個弱引用,那麼也許會更好(更簡單?)? – SoCal

相關問題