Wednesday, March 14, 2012

How to create our own listeners in java?


Listener is an implemented interface, which reacts to some event. For example, if you press a button, or scroll your mouse, or select an item from a combobox, they all create an event, and all the Listeners which are listening to the current Object will be notified.

Let's say your grandmother is baking cookies. You don't know exactly when the cookies are ready, so you call her every two minutes to check if the cookies are ready, because you need them immediately after baking. You also have other things to do and don't want to waste your resources on calling, so it doesn't seem like a very good solution to constantly call her. Better solution would be to give your grandmother an instruction (implement a listener) to call you immediately after the cookies are ready. Because she knows exactly when the cookies will be ready, she doesn't need to call you more than once and everybody's resources and time are saved.

I'm going to show how to create such Listeners and logic behind them for your own classes.

I have a class named Grandmother. Its purpose is to run and create cookies.
However, it extends a Thread class, which means it runs independently from the main thread and thus creates cookies at random times.

I've tried to keep this as simple as possible:
import java.util.LinkedList;

public class Grandmother extends Thread{
    // GRANNY STUFF    
    private final int MAX_SLEEP = 5000;
    private final int MAX_COOKIES = 25;    
        
    private void cook(){
        int cookies = (int)(Math.random()*MAX_COOKIES-1)+1;    
        
        for(GrannyListener t: grannyListeners){
            t.cookiesBaked(new CookieEvent(cookies));
        }
    }
    
    // GRANNY THREAD
    public void run(){        
        while(true){            
            try {
                sleep((int)(Math.random()*MAX_SLEEP));
            } catch (InterruptedException e) {    }
            cook();
        }
    }    
    
    
    //LISTENER STUFF    
    private LinkedList<GrannyListener> grannyListeners = new LinkedList<GrannyListener>();
    
    public void addGrannyListener(GrannyListener listener){
        grannyListeners.add(listener);
    }
    
    public boolean removeGrannyListener(GrannyListener listener){
        return grannyListeners.remove(listener);
    }    
}


Granny has a method run(), which starts the thread and locks it into an infinite loop, where it sleeps for random time between 0-5000 ms and calls the cook() method. In this method the thread produces random amount of cookies between 1-25 and iterates over the grannyListeners List, notifying every one, that she has produced cookies. Notice, that on the bottom side i have the listener side of the logic. There is a LinkedList of listeners(LinkedList is perfect for fast insertion and removal) and there's two methods for adding and removing the GrannyListeners.

So, what does GrannyListener look like? It's actually very simple interface, containing only one method with empty body.
public interface GrannyListener {
    public void cookiesBaked(CookieEvent e);    
}


It states that every GrannyListener must implement a method called cookiesBaked(), which takes CookieEvent as an argument.

CookieEvent is a class which holds information about manufacturing date and amount of the cookies produced.
import java.util.Date;

public class CookieEvent {    
    
    private Integer amount;    
    private Date date;
    
    public CookieEvent(Integer amount){        
        this.date = new Date();
        this.amount = amount;
    }
    
    public Integer getAmount(){
        return amount;
    }    
    
    public Date getDate(){
        return date;
    }
}
If we look at the GrandMother's code again, we will see that in the cook() method, it iterates over every GrannyListener, and calls the cookiesBaked method with new CookieEvent, thus creating a new instance of object for every listener. I believe this is good practice in case event contains some information that might be modifiable.
private void cook(){
        int cookies = (int)(Math.random()*MAX_COOKIES-1)+1;    
        
        for(GrannyListener t: grannyListeners){
            t.cookiesBaked(new CookieEvent(cookies));
        }
    }


Now, we are just missing the actual Demo program, which tests the whole thing. Lets see:
public class Demo {
    final static Grandmother granny = new Grandmother();
    public static int totalCookies=0; 
    
    public static void main(String[] args) {    
        GrannyListener grannyListener = 
            new GrannyListener(){    
                
                @Override
                public void cookiesBaked(CookieEvent e) {
                    int amount = e.getAmount();
                    System.out.println("Granny said that she produced "+amount+" "+(amount > 1?"cookies":"cookie")+" at "+e.getDate());
                    addCookiesToJar(amount);
                    System.out.println("Granny has produced total of "+totalCookies+" "+(totalCookies > 1?"cookies":"cookie")+".\n");
                }                                
            };
        
        granny.addGrannyListener(grannyListener);        
        
        granny.run();
    }
    
    public static void addCookiesToJar(int amount){
        totalCookies+=amount;    
        
    }
}


I have a static granny and some static data about total amount of cookies produced. In the main method we will see that i'm implementing a new GrannyListener. I am Overriding the empty body method
cookiesBaked() and adding my own data there, which will be executed every time by GrandMother if she makes some cookies. After that i am adding the listener to the actual grandmother's list using the
addGrannyListener method, which i explained before. And finally i am executing the granny's Thread.

if you care, what the output looks like:


Granny said that she produced 7 cookies at Mon Sep 06 18:31:59 EEST 2010
Granny has produced total of 7 cookies.

Granny said that she produced 9 cookies at Mon Sep 06 18:32:03 EEST 2010
Granny has produced total of 16 cookies.

Granny said that she produced 1 cookie at Mon Sep 06 18:32:07 EEST 2010
Granny has produced total of 17 cookies.

Granny said that she produced 18 cookies at Mon Sep 06 18:32:07 EEST 2010
Granny has produced total of 35 cookies.

Granny said that she produced 21 cookies at Mon Sep 06 18:32:09 EEST 2010
Granny has produced total of 56 cookies.


No comments:

Post a Comment