Complete Guide > Life cycle listeners

Introduction to events

EpochX has an event handling mechanism which provides a way of listening for life cycle events such as the start of a crossover operation or the end of a generation. This is a powerful tool for interacting with the framework while it runs. The two most common uses of the life cycle listeners are for generating output at regular intervals and for modifying the run parameters dynamically.

All life events are handled by an instance of the Life class. Infact, we can refer to it as the instance of the Life class, since it implements the singleton pattern and so there is only ever one Life object. You can obtain a reference to this instance from anywhere with a call to the static method Life.get(). The Life class has a series of addXxxListener methods for adding listeners for different classes of event. The following is a list of the standard addXxxListener methods.

  • addCrossoverListener(CrossoverListener)
  • addElitismListener(ElitismListener)
  • addGenerationListener(GenerationListener)
  • addInitialisationListener(InitialisationListener)
  • addMutationListener(MutationListener)
  • addPoolSelectionListener(PoolSelectionListener)
  • addReproductionListener(ReproductionListener)
  • addRunListener(RunListener)

Each of these methods takes a listener instance. As is often the case with the listener pattern, it would be typical to use an anonymous class that implements the listener interface. As such, an XxxAdapter abstract class exists for each XxxListener that implements that interface providing empty methods for each of the events. This makes it much more convenient to extend XxxAdapter, overriding only those methods for the events you are interested in. For example, the following code might be used to listen for crossover end events.

Life.get().addCrossoverListener(new CrossoverAdapter(){
    public void onCrossoverEnd() {
        // ...code to be executed at the end of each crossover.

Config events

In addition to the above classes of event, there is also one other type of event; the config event. Listeners for the config event can be added in the same way, with the addConfigListener(ConfigListener) method. ConfigListener only defines one method - onConfigure. This event is caused to fire at the following times:

  • At the start of a series of runs.
  • At the start of each run.
  • At the start of initialisation and each generation.
  • When manually fired.

When using the built-in components and operators provided with EpochX, there is probably no need to use config events at all. Their use will happen in the background. But, if you find yourself implementing a new operator, you might want to consider using them. A detailed description of how to go about this will be covered in a later tutorial, but it is worth describing the concept here. All built-in components and operators that require parameters have two forms of construction. They can either be constructed with the parameter values themselves, or with a reference to a model. In the latter case, they obtain the parameter values they need from the model and refresh the parameter values they are using upon every config event. As already mentioned in the Models chapter, this allows models to dynamically change their values and have the new value used from the next config event.

Although not usually necessary, it is possible to force operators to update their parameter values from the model more frequently than at each generation by firing the config event manually. This can be done with the following statement: Life.get().fireConfigureEvent();

Strong and weak listeners

In truth, the addXxxListener methods above are only half the story, because for each one that takes just an XxxListener, there is another version which also takes a boolean value. The boolean is an indicator for whether a strong reference should be maintained to the listener as it is stored in the Life object. If the value is false then only a weak reference will be maintained. Most users should simply use the standard addXxxListener method, which will use a strong reference by default. In some extreme cases it may be possible to introduce a memory leak when adding listeners and not removing them once finished, by using a weak reference they will automatically be removed when possible. This is something that should simply be ignored by most users, it is mentioned here mainly for completeness.

Next: Statistics
Previous: Algorithm