Simplifying Interval Updates

The Interval class simplifies how you use timers and enter frame events when you need constant updates.

The Interval class also stores a map of the intervals created using the static Interval.getIntervalByRate( rate ) method. If you request two Intervals of the same rate using the getIntervalByRate method you will have references to the same Interval.

When an Interval is not running at the Interval.FRAME_RATE you can force screen updates using the updateAfterEvent() method in the IntervalEvent that is dispatched.


package com.iamavila.utils
{
	import com.iamavila.events.IntervalEvent;
	
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.events.TimerEvent;
	import flash.utils.Timer;

	/**
	 * The Interval class provides a simple interface for running code at a specified rate. You specify
	 * the rate of the Interval when creating it. The rate can be in milliseconds or the constant
	 * Interval.FRAME_RATE which represents the frame rate of the application. An Interval object will
	 * dispatch IntervalEvent.INTERVAL events for as long as an object is listening to it.
	 * 
	 * The Interval class also provides a static method getIntervalByRate for retrieving a stored interval.
	 * 
	 */
	public class Interval extends EventDispatcher
	{
		/**
		 * Represents the frame rate of the applicatioin.
		 */
		public static const FRAME_RATE:int = -1;
		
		private static var intervals:Object;
		
		/**
		 * The Interval class stores a map of all intervals created using this method so that only
		 * one interval object exists for each rate. If you want all animations running on the same frame
		 * rate interval you would request Interval.getIntervalByRate( Interval.FRAME_RATE ).
		 */
		public static function getIntervalByRate( rate:int ):Interval
		{
			if ( !intervals )
				intervals = new Object();
				
			if ( !intervals[ rate ] )
				intervals[ rate ] = new Interval( rate );
			
			return intervals[ rate ];
		}
		
		private var _rate:uint;
		/**
		 * The rate in milliseconds at which the Interval is running. -1 represents the frame rate
		 * of the application. 
		 */
		public function get rate():int { return _rate; }
		
		private var dispatcher:IEventDispatcher;
		private var intervalEventType:String;
		
		/**
		 * Creates a new Interval object for the specified rate. Once an Interval object
		 * has been created you can begin listening for IntervalEvent.INTERVAL events.
		 * 
		 * @param int The rate at which the Interval will dispatch IntervalEvent.INTERVAL events.
		 */
		public function Interval( rate:int )
		{
			initialize( rate );
		}
		
		/**
		 * @inheritDoc
		 */
		public override function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false):void
		{
			// if no one is listening to the interval start listening to the dispatcher
			if ( !hasEventListener( intervalEventType ) )
			{
				// if the dispatcher is a timer we have to start it manually
				if ( rate != FRAME_RATE )
					Timer( dispatcher ).start();
					
				dispatcher.addEventListener( intervalEventType, triggered );
			}
			
			super.addEventListener( type, listener, useCapture, priority, useWeakReference );
		}
		
		/**
		 * @inheritDoc
		 */
		public override function removeEventListener(type:String, listener:Function, useCapture:Boolean=false):void
		{
			super.removeEventListener( type, listener, useCapture );
			
			// if no one is listening to the interval stop listening to the dispatcher
			if ( !hasEventListener( intervalEventType ) )
			{
				// if the dispatcher is a timer we have to stop it manually
				if ( rate != FRAME_RATE )
					Timer( dispatcher ).stop();
					
				dispatcher.removeEventListener( intervalEventType, triggered );
			}
		}
		
		private function initialize( rate:int ):void
		{
			_rate = rate;
			
			if ( rate == FRAME_RATE )
			{
				dispatcher = new Sprite();
				intervalEventType = Event.ENTER_FRAME;
			}
			else
			{
				dispatcher = new Timer( rate );
				intervalEventType = TimerEvent.TIMER;
			}
		}
		
		private function triggered( event:Event ):void
		{
			var e:IntervalEvent = new IntervalEvent( IntervalEvent.INTERVAL );
		
			if ( rate != FRAME_RATE )
				e.updateAfterEventSource = event as TimerEvent; 
			
			dispatchEvent( e );
		}
	}
}

Once an Interval is created you just have to start listening to it. An Interval will not be active while no one is listening to it.

Simple demo


package
{
	import com.iamavila.events.IntervalEvent;
	import com.iamavila.utils.Interval;
	
	import flash.display.Sprite;

	public class IntervalDemo extends Sprite
	{	
		public function IntervalDemo()
		{
			var i:Interval = Interval.getIntervalByRate( 1000 );
			i.addEventListener( IntervalEvent.INTERVAL, interval );
			
			// to stop listening
			// i.removeEventListener( IntervalEvent.INTERVAL, interval );
		}
		
		private function interval( event:IntervalEvent ):void
		{
			trace( "update" );
		}
	}
}