fireEvent() and custom Listeners
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?
peter_budo
Code tags enforcer
15,436 posts since Dec 2004
Reputation Points: 2,806
Solved Threads: 902
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);
}
JamesCherrill
Posting Genius
6,371 posts since Apr 2008
Reputation Points: 2,130
Solved Threads: 1,073
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 :)
di2daer
Junior Poster in Training
66 posts since Sep 2008
Reputation Points: 22
Solved Threads: 13
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?
peter_budo
Code tags enforcer
15,436 posts since Dec 2004
Reputation Points: 2,806
Solved Threads: 902
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);
}
JamesCherrill
Posting Genius
6,371 posts since Apr 2008
Reputation Points: 2,130
Solved Threads: 1,073
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);
}
}
__avd
Posting Genius (adatapost)
8,648 posts since Oct 2008
Reputation Points: 2,136
Solved Threads: 1,241
BestJewSinceJC
Posting Maven
2,772 posts since Sep 2008
Reputation Points: 874
Solved Threads: 354
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.
JamesCherrill
Posting Genius
6,371 posts since Apr 2008
Reputation Points: 2,130
Solved Threads: 1,073
peter_budo
Code tags enforcer
15,436 posts since Dec 2004
Reputation Points: 2,806
Solved Threads: 902