How to add listener on ArrayList in java

心不动则不痛 提交于 2019-11-27 04:47: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 understand that I can't extend ArrayList and then add listener.

I want to use MyList in class as a variable with public modifier, so users can change it directly and to be done action when he changes it.

class MyList extends ArrayList<object>.... {  ... }
 class UseOfMyList {
 public MyList places = new MyList<Object>();
 places.add("Buenos Aires");
 //and to be able to do that
 List cities = new ArrayList<Object>();
 cities.add("Belmopan");
 places = cities;

So how to create and when do add,remove or pass another list to MyList an action to be performed?


回答1:


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
    }
}



回答2:


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

}



回答3:


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

}


来源:https://stackoverflow.com/questions/16529273/how-to-add-listener-on-arraylist-in-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!