I'm trying to get hang of custom events and listeners. I found example of single event-listener, but I'm curious how to extend from single method to multiple that are related.

public interface CountListener{
	
	public void countEvent(int count);
	
	public void multiplyEvent(int multi);    
}
public class Counter implements CountListener{

    public void countEvent(int count){
    	System.out.println("Counter: "+count);
    }
    
    public void multiplyEvent(int multi){
    	System.out.println("Multiply: " +multi*multi);
    }
}
import java.util.*;
import java.lang.reflect.Method;

public class CountTest {

    ArrayList listeners;
    
    public void addCountListener(CountListener c){
    	listeners.add(c);
    }
    
    public void removeCountListener(CountListener c){
    	if(listeners.contains(c)){
    		listeners.remove(listeners.indexOf(c));
    	}
    }
    
    public void fireEvent(int count, Object methodObj){
    	Iterator i = listeners.iterator();
    	while(i.hasNext()){    		
    		//((CountListener)i.next()).countEvent(count);
    		Object obj = i.next();
    		System.out.println(obj.getClass().getName());
    		
    		Method[] meth = obj.getClass().getDeclaredMethods();
    		for(Method m : meth){
    			
    			if(m.equals(methodObj)){
    				System.out.println(m.getName());
    				try{
    					m.invoke(methodObj, count);
    				}
    				catch(Exception e){
    				}
    			}
    		}
    	}
    }
    
    public CountTest(){
    	listeners = new ArrayList();
    }
    
    public void count(int i){
    	fireEvent(i, (Object) "countEvent");
    }
    
    public void multiply(int i){
    	fireEvent(i, (Object) "multiplyEvent");
    }
    
    public static void main(String[] args){
    	CountTest c = new CountTest();
    	c.addCountListener(new Counter());
    	
    	/*for(int i = 0; i < 10; i++){
    		c.count(i);
    	}*/
    	c.count(5);
    	c.multiply(5);
    }
}

As you can see from above example I'm able to break down class on all methods provided by this class. However I'm not bale to call appropriate method that much my listener call. fireEvent(i, (Object) "countEvent"); is just blatant attempt because I know compile will not fire errors. So question is how do I declare this Object so it will work? Or am I completely of the hock with my attempt?

I can't understand what you are trying to do with all the Reflection methods here! What do you need to do that is different from the standard pattern:

ArrayList<CountListener> listeners = new ...

...

void fireCountEvent(int count) {
   for (CountListener cl : listeners) {
      cl . countEvent(count);
   }
}

...

void fireMultiplyEvent(int mult) {
   for (CountListener cl : listeners) {
      cl . multiplyEvent(mult);
   }
}

public void count(int count) {
   ...
   fireCountEvent(count);
}

In your code you have the wrong comparisson:
m.equals(methodObj) should be m.getName().equals(methodObj)
since m contains "public void bla bla()"

And when you invoke the method you need to invoke it with an instance of the class, e.g: m.invoke(new Counter(), count);

I think :)

I can't understand what you are trying to do with all the Reflection methods here!

Just trying to fill in empty spaces in my knowledge. Above example op-up on Google search and I tried to expand, unfortunately I may not chosen wisely.

In your code you have the wrong comparisson:
m.equals(methodObj) should be m.getName().equals(methodObj)
since m contains "public void bla bla()"

And when you invoke the method you need to invoke it with an instance of the class, e.g: m.invoke(new Counter(), count);

I think :)

Correct assumption. It did work.

However James proposal is better approach at this point. Or has anybody better idea?

James proposal is better approach at this point.

Sorry, I can't take any credit for that - it's just the standard boiler-plate way of doing it. One small tweek: there's a danger of a problem if the list of Listeners is updated while the fireEvent code is looping through it (either because its multi-threaded, or maybe because a listener receives the event and, in the event handling method, decides to remove itself from the list). For that reason it's normal to use a temporary copy for the loop:

ArrayList<CountListener> safeCopy = new ArrayList<CountListener>(listeners);
   for (CountListener cl : safeCopy ) {
      cl . countEvent(count);
   }

I have added the JC's suggestion.

I think two method of CountListener interface has no value and also I have added CountEvent object as an argument of event method.

public interface CountListener{
        public void countEvent(CountEvent e);
}
public class CountEvent{
   private int result;
   private String action;
   private Object source;
   public CountEvent(int result,String action,Object source) {
      this.result=result; this.action=action; this.source=source;
   }
   public int getResult() { return result;}
   public String getAction() { return action;}
   public Object getSource() { return source;}
}
public class Counter implements CountListener{
    public void countEvent(CountEvent e){
        System.out.println(e.getResult() + " " + e.getAction());
    }
}
import java.util.*;

public class CountTest {

    ArrayList<CountListener> countlisteners;
    
    public void addCountListener(CountListener c){
        if(countlisteners==null)
             countlisteners=new ArrayList<CountListener>();
    	countlisteners.add(c);
    }
   
    public void removeCountListener(CountListener c){
    	if(countlisteners.contains(c)){
    		countlisteners.remove(countlisteners.indexOf(c));
    	}
    }
    
    public CountTest(){
    }
    
    public void count(int i){
         ArrayList<CountListener> safeCopy = new 

ArrayList<CountListener>(listeners);
         for(CountListener c:safeCopy) {
            if(c!=null) c.countEvent(new CountEvent(i,"Count",this));
         }
    }
   
    public void multiply(int i){
      ArrayList<CountListener> safeCopy = new 
ArrayList<CountListener>(listeners);
         for(CountListener c:safeCopy) {
            if(c!=null) c.countEvent(new CountEvent(i,"Mul",this));
         }
    }
   
    public static void main(String[] args){
    	CountTest c = new CountTest();
        Counter t=new Counter();
        c.addCountListener(t);
    	
        c.count(2);
    	c.multiply(5);
        c.removeCountListener(t);
        c.count(22);
        c.multiply(55);
    }
}

I like the solution with a custom event class to carry the info to the listeners. Very nice. Particularly good if there is any chance that there will be more functionality added later, because you can add more event sub-types without changing the formal definition of the listener interface and thus invalidating existing code.

This article has been dead for over six months. Start a new discussion instead.