How to add listener on ArrayList in java

前端 未结 3 717
予麋鹿
予麋鹿 2020-12-06 18:56

I want to create my own implementation of ArrayList in java, that can listen when the list is changing and to do action when this happens. From what I have read, I understan

相关标签:
3条回答
  • 2020-12-06 19:22

    You're not going to be able to do this by extending ArrayList, as it has no built-in notification mechanism (and, further, because it is has been declared final and thus cannot be extended). However, you can achieve your desired result by creating your own List implementation and adding your "listener" functionality vis a vis the add() and remove() methods:

    class MyList<T>{
        private ArrayList<T> list;
    
        public MyList(){
            list = new ArrayList<>();
            ...
        }
        public void add(T t){
            list.add(t) 
            //do other things you want to do when items are added 
        }
        public T remove(T t){
            list.remove(t);
            //do other things you want to do when items are removed
        }
    }
    
    0 讨论(0)
  • 2020-12-06 19:39

    Old question, I know. I apologize in advance for any bad formatting or missing lines of code. I'm a long-time user, first time contributor.

    Anyhow, because of the removal of JavaFX from the JDK11, I was forced to write my own version of the ObservableList. Sure, we can plop JavaFX in with JMods or Maven, but it seems like a bit of an overkill just for the FXCollections.

    Long Story made Short...er :)

    I started out reading this old question and the answer didn't suit my needs fully, so I've added a custom event/listener class.

    Figured I could share since this site has improved my coding 10 fold.

    public static void main(String[] args) {        
        BackedList<String> list = new BackedList();
        list.addListener(new BackedListListener<String>(){
            @Override
            public void setOnChanged(ListChangeEvent<String> event) {
                if (event.wasAdded()) {
                    event.getChangeList().forEach(e->{
                       // do whatever you need to do                        
                        System.out.println("added: " + e);
                    });
                }
                if (event.wasRemoved()) {
    
                    // do whatever you need to dl
                    event.getChangeList().forEach(e->{System.out.println(e + " was removed");});
                }
            }
        });
    

    Class: BackedObservableList

        public class BackedObservableList<T> implements List<T> {
            private final List<T> backed;
    
        public BackedObservableList() {
            backed = new ArrayList();
        }
    
        public BackedObservableList(List<T> backed) {
            this.backed = backed;
        }
    
            /*
    
            You will want to override every method. For any method that performs an add/remove 
            operation, you will have to do some coding / testing. I'll do an add() op, a remove() 
            op, and an interator in this example. Anything that is not an add/remove op, you can straight up delegate it to the underlying list. 
    Also remember that list.clear() is a removal operation, where you can simply iterate through the backed list and call the overide remove(T t) method, or just plop the whole backed list into the ListChangeEvent<T> class and delegate to the backed array again.
    
    
                    */
    
    
         @Override
            public boolean add(T e) {
                if (backed.add(e)) {
                    ListChangeEvent<T> event = new ListChangeEvent(this, backed.indexOf(e), backed.indexOf(e) + 1, true, e);
                        notifyListeners(event);
                    return true;
                    }
                return false;
                    }
    
            }
    
        @Override
        public boolean remove(Object o) {
            if (backed.remove(o)) {
                ListChangeEvent<T> event = new ListChangeEvent(this, backed.indexOf(o), 
    
        backed.indexOf(o) + 1, false, o);
                    notifyListeners(event);
                    return true;
                }
                return false;
            }
        /*
    
        The iterator seemed easy enough, until I remembered the iterator.remove() call. 
        I still haven't fully tested it (it works, but only as far as I've used it)
    
        */
         @Override
            public Iterator<T> iterator() {        
                return new Iterator<T>() {
                    T currentItem = null;
                    int currentIndex = 0;
    
                @Override
                public boolean hasNext() {
                    return backed.size() > currentIndex;
                }
    
                @Override
                public T next() {
    
                    return currentItem = backed.get(currentIndex++);
                }
    
                @Override
                public void remove() {
                    if (backed.remove(currentItem)) {
                        currentIndex--;
                        notifyListeners(new ListChangeEvent<T>(backed, currentIndex, currentIndex + 1, false, currentItem));
                    }
                }
            };
        }
    
    
         private void notifyListeners(ListChangeEvent<T> event) {
                for (BackedListListener<T> listener : listeners) {
                    listener.setOnChanged(event);
                }
            }
    
            private final List<BackedListListener> listeners = new ArrayList();
    
            public void addListener(BackedListListener<T> listener) {
                listeners.add(listener);
            }
    

    Class: ListChangeEvent

    It simply provides a reference to the backed list (which you may want to wrap with Collections.unmodifiableList()

    public class ListChangeEvent<T> {
    private final List<T> source;
    private final List<T> changeList;
    private final boolean wasAdded;    
    private final int to, from;
    
    public ListChangeEvent(List<T> source, int from, int to, boolean wasAdded, T... changeItems) {
        this(source, from, to, wasAdded, Arrays.asList(changeItems));
    }
    
    
        public ListChangeEvent(List<T> source, int from, int to, boolean wasAdded, List<T> changeItems) {
            this.source = source;
            this.changeList = changeItems;
            this.wasAdded = wasAdded;
            this.to = to;
            this.from = from;                
        }
    
        public int getFrom() {
            return from;
        }
    
        public int getTo() {
            return to;
        }
    
        public List<T> getSource() {
            return source;
        }
    
        public List<T> getChangeList() {
            return changeList;
        }
    
        public boolean wasAdded() {
            return wasAdded;
        }
    
        public boolean wasRemoved() {
            return !wasAdded;
        }            
    }
    

    Class: BackedListListener

        /*
        Finally a little functional interface... or, because I was too lazy to change it to one, a simple one-liner abstract class with some generics
        */
        public abstract class BackedListListener<T> {
    
        public abstract void setOnChanged(ListChangeEvent<T> event);        
    
    }
    
    0 讨论(0)
  • 2020-12-06 19:39

    the resp. ;)

    private class MyList extends ArrayList<Objects> {
    
          @Override
          public void sort(Comparator c) {
            super.sort(c); 
            resetLancamentos(); // call some metod ;)
          }
        //...
         @Override
         public boolean removeAll(Collection c) {
            //To change body of generated methods, choose Tools | Templates.
            boolean ret = super.removeAll(c);
            resetLancamentos(); // some metod like fireObjChanged() will do the job too
             return ret;
         }
    
    }
    
    0 讨论(0)
提交回复
热议问题