git.net

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Memory Leak


By way of example here is a sample class I have created. The killMe method is
an attempt to make the GC want to take out the trash.

package Classes.Input
{
	import flash.events.DataEvent;
	import flash.events.Event;
	import flash.events.FocusEvent;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.ui.Keyboard;
	import flash.utils.Dictionary;
	
	import mx.controls.ComboBox;
	import mx.events.ListEvent;
	
	/**
	 * postValidate Code to execute after validateData method completes.
	 * 
	 **/

	[Event(name="postValidate", type="flash.events.DataEvent")]
	
	/**
	 * Create an extended version of the ComboBox that allows the definition of
invalid indexes and
	 * multiple keystroke selection.
	 * 
	 * <pre>
	 * The developer defines one or more invalid indexes in a comma separated
list using the property badIndexes.
	 * Most commonly the developer would specify "0" which is the first element
in the list.
	 * 
	 * New properties are;
	 * badIndexes - A string that allows the developer to define a comma
separated list of invalid indexes.
	 * isVald - A boolean that defines whether the field is valid.
	 * 
	 * New Methods are;
	 * validateData() - This method checks if the data is valid and returns
true if valid, false if invalid.
	 * 
	 * Enhanced Properties;
	 * value - When the property value is set, the combobox will attempt to
find the appropriate value in the 
	 * dataprovider, and set the selectedIndex to that item. It will set the
value to -1 if not found.
	 * 
	 * </pre>
	 */
	public class ValidatedComboBox extends ComboBox
	{
		/** Bad indexes - A comma separated list of invalid indexes. */
		private var _badIndexes:String = "";
		
		/** Bad Data - A comma separated list of invalid Data. */
		private var _badData:String = "";
		
		/** Has this field passed validation */
		private var _isValid:Boolean = true;
		
		/** value */
		private var _value:Object;
		
		/** should we validate data */
		private var _doValidateData:Boolean = true;
		
		/** promptLabel */
		private var _promptLabel:String;
		
		
		/** dataType */
		private var _dataType:String = "string";
		
		/** dataField */
		private var _dataField:String = "DATA";
		
		/** toolTipField */
		private var _toolTipField:String = "";
		
		/** Default value A literal that represents the value that will replace
the "value"
		 * property when the method setDefault is executed */
		private var _defaultValue:String = "";
		
		private var _eventHandler:Function = this["checkData"];
		
		private var _tabOut:Function = null;
		
		private var _focusOutTab:Boolean = false;

		private var _typedText:String = "";
		
		public function ValidatedComboBox()
		{
			//TODO: implement function
			super();
			this.addEventListener(Event.CHANGE,_eventHandler,false,0,true)
		}
	    override protected function createChildren():void
	    {
	        super.createChildren();
			
			if(this.textInput)
			{ // Use ValidatedTextInput instead of TextInput and Setup various fields 
				textInput["id"] = "vti" + this.id;
//				textInput.parentDrawsFocus = true;
			}
	    }
		
		/**
		 * badIndexes- A comma seperated list of indexes that will be considered
invalid. 
		 * 
		 * @return the specified bad indexes
		 */
		[Inspectable( type="String" , defaultValue="" )]
		public function get badIndexes():String 
		{
			return this._badIndexes;
		} 
		/**
		 * Sets the the specified bad indexes
		 */
		public function set badIndexes( badIndexes:String ):void 
		{
			this._badIndexes = badIndexes;
			if (_badIndexes.length < 1)
			{
				errorString = "";
				_isValid = true;
			}
		}
		
		/**
		 * badData- A comma seperated list of Data that will be considered
invalid. 
		 * 
		 * @return the specified bad Data
		 */
		[Inspectable( type="String" , defaultValue="" )]
		public function get badData():String 
		{
			return this._badData;
		} 
		/**
		 * Sets the the specified bad Data
		 */
		public function set badData( badData:String ):void 
		{
			this._badData = badData;
			if (_badData.length < 1)
			{
				errorString = "";
				_isValid = true;
			}
		}
		
		/**
		 * promptLabel - Specify a human readable label for the field.
		 * 
		 * @return the specified promptLabel
		 */

		[Inspectable( type="String" , defaultValue="" )]
		public function get promptLabel():String 
		{
			return this._promptLabel;
		} 
		/**
		 * Sets the the specified promptLabel
		 */
		public function set promptLabel( promptLabel:String ):void 
		{
			this._promptLabel = promptLabel;
		}
		
		/**
		 * dataType - specify whether to use numeric or string matching when
setting
		 * the value of this field.
		 * 
		 * <p>
		 * Use this field when the drop down's data is a number. Particularly
useful if 
		 * the current field in the database is string and can contain leading
zeroes.
		 * </p>  
		 * 
		 * @return the specified validate data flag.
		 */
		[Inspectable( type="String" , defaultValue=false,
enumeration="string,number" )]
		public function get dataType():String
		{
			return this._dataType;
		}
		
		/**
		 * Sets the specified validate data flag.
		 */
		public function set dataType( dataType:String ):void 
		{
			this._dataType = dataType;
		}
		
		/**
		 * doValidateData - specify the whether this field should be validated.
Default is true. 
		 * 
		 * @return the specified validate data flag.
		 */
		[Inspectable( type="Boolean" , defaultValue=false,
enumeration="true,false" )]
		public function get doValidateData():Boolean 
		{
			return this._doValidateData;
		}
		
		/**
		 * Sets the specified validate data flag.
		 */
		public function set doValidateData( doValidateData:Boolean ):void 
		{
			this._doValidateData = doValidateData;
		}
		
		/**
		 * toolTipField - Specify a field in the dataProvider whose value will be
used as the
		 * to populate the toolTip. 
		 * 
		 * @return the specified toolTipField
		 */
		[Inspectable( type="String" , defaultValue="" )]
		public function get toolTipField():String 
		{
			return this._toolTipField;
		} 
		/**
		 * Sets the the specified toolTipField
		 */
		public function set toolTipField( toolTipField:String ):void 
		{
			this._toolTipField = toolTipField;
		}
		
		/**
		 * defaultValue - allows the specification of a default value for a field.
		 * To set the current text/value properties use the the setDefault()
method.
		 * 
		 * @return the specified defaultValue value
		 */
		[Inspectable( type="String" , defaultValue="" )]
		public function get defaultValue():String 
		{
			return this._defaultValue;
		} 
		/**
		 * Sets the specified Default value
		 */
		public function set defaultValue( defaultValue:String ):void 
		{
			this._defaultValue = defaultValue;
			var event:Event;
		}
		
		/**
		 * dataField - the field to be used as the data field from the
dataProvider.
		 * 
		 * The value of the field defined here is what the value is set to based 
		 * on the selection.  
		 * 
		 * @return the specified dataFiel
		 */
		[Inspectable( type="String" , defaultValue="DATA" )]
		public function get dataField():String 
		{
			return this._dataField;
		} 
		/**
		 * Sets the the specified dataField
		 */
		public function set dataField( dataField:String ):void 
		{
			this._dataField = dataField;
		}
		
		/**
		 * tabOut - A function to execute if the tabkey is pressed..
		 * 
		 * @return the specified tabOut Function
		 */
		[Inspectable( type="Function" , defaultValue="" )]
		public function get tabOut():Function 
		{
			return this._tabOut;
		} 
		/**
		 * Sets the the specified tabOut
		 */
		public function set tabOut( tabOut:Function ):void 
		{
			this._tabOut = tabOut;
		}
		
		/**
		 * focusOutTab - A boolean defining if the last focus out was a tab.
		 * 
		 * @return  focusOutTab
		 */
		public function get focusOutTab():Boolean
		{
			return this._focusOutTab;
		} 
		/**
		 * Sets the the specified focusOutTab
		 */
		public function set focusOutTab( focusOutTab:Boolean ):void 
		{
			this._focusOutTab = focusOutTab;
		}

		/**
		 * isValid - Returns a boolean that defines whether the current value is
valid.
		 */

		public function get isValid():Boolean 
		{
			return _isValid;
		}
		
		override public function get value():Object
		{
			return _value;
		}
		
		override public function set dataProvider(dpValue:Object):void
		{
			var objCurrentValue:Object = _value;
			super.dataProvider = dpValue;
			if (this.hasOwnProperty("dropdown"))
				if (this.dropdown != null)this.dropdown.dataProvider = dpValue;
			_value = objCurrentValue;
			if (dpValue != null)
			{
				if (dpValue.length > 0)
				{
					if (_value != null) 
					{
						if(_value.toString().length > 0) setSelectedItem(_value);
					}
					else
					{
						if (this.selectedItem != null) _value = this.selectedItem[dataField];
					}
		 			if (this.selectedIndex == -1)
					{
						this.selectedIndex = 0;
						_value = this.selectedItem[dataField];
						if (this.selectedItem != null)
							if (this.selectedItem.hasOwnProperty(dataField))
							{
								_value = this.selectedItem[dataField];
								dispatchEvent( new ListEvent( ListEvent.CHANGE ) );
							} 
					}
				}
			}
			dpValue = null;
			objCurrentValue = null;
		}
		
		override public function set selectedIndex(intValue:int):void
		{
//			if (this.hasOwnProperty("id")) trace("id=" + this.id + " set intValue="
+ intValue);
			super.selectedIndex = intValue;
			if (intValue > -1)
			{
				if (this.selectedItem != null)
				{
					if (this.selectedItem.hasOwnProperty(dataField))
					{
						 _value = this.selectedItem[dataField];
					}
				}
			}
		}
		
		/**
		 * Sets the the specified value based on the item selected.
		 */
		
		public function set value(value:Object): void
		{
//			if (this.hasOwnProperty("id")) trace("id=" + this.id + " set value=" +
value);
//			trace("ValidatedComboBox-" + this.id + "Set value=" + value);
			this.selectedIndex = 0;
			if (value != null)
			{
				setSelectedItem(value);
				_value = value;
			}
			else
			{
				_value = "";
			}
 			if (this.selectedIndex > -1)
			{
				if (this.selectedItem != null)
					if (this.selectedItem.hasOwnProperty(dataField))
					{
						 _value = this.selectedItem[dataField];
					}
			}
		}

		private function checkData(event:Event):void
		{
			this.removeEventListener(Event.CHANGE,_eventHandler)
			if (this.selectedItem)
			{
				this.
				_value = this.selectedItem[dataField];
				validateData();
			}
			this.addEventListener(Event.CHANGE,_eventHandler,false,0,true)
		}

		/**
		 * setDefault - Method that will replace the value of the value property
with the 
		 * value of the defaultValue property.
		 */
		 
		public function setDefault():void
		{
			_value = _defaultValue;
			setSelectedItem(_value);
		}
		
		/**
		 * getDefault - Method that will return the value of the defaultValue
property.
		 * 
		 * This method returns the defaultValue it exists to provide a consistenet
api
		 * between all "validated" components.
		 */
		 
		public function getDefault():String
		{
			return _defaultValue;
		}

		/**
		 * validateData - Method that will validate the data that has been
entered.
		 */

		public function validateData():Boolean
		{
			if (_badIndexes.length == 0 && _badData.length == 0) 
			{
				this.dispatchEvent(new DataEvent("postValidate"));
				return true;
			}
			var aryIndexesTemp:Array = _badIndexes.split(",");
			if (_doValidateData)
			{
				_isValid = ((aryIndexesTemp.indexOf(this.selectedIndex.toString()) ==
-1) &&
							(this.selectedIndex > -1));
				if (_isValid && _badData.length > 0)
				{
					var aryDataTemp:Array = _badData.split(",");
					if (this.selectedIndex > -1) _isValid =
(aryDataTemp.indexOf(this.dataProvider[this.selectedIndex][dataField].toString())
== -1);
				}
				if (!_isValid) 
				{
					this.errorString = '"' + this.selectedLabel + '" is an invalid choice.
' + 
											 this.selectedLabel.toString();
				}
				else
				{
					this.errorString = "";
				}
			}
			this.dispatchEvent(new DataEvent("postValidate"));
			return _isValid;
		}


		private function setSelectedItem(strFindItem:Object):void
		{
			var strDataItem:String = "";
			if (this.dataProvider != null)
			{
				this.selectedIndex = -1;
				if (_dataType == "number")
				{
					strFindItem = String(parseInt(strFindItem.toString(),10));
				} 
				for (var i:int=0;i<this.dataProvider.length;i++)
				{
					if (this.dataProvider[i] != null)
					{
						if (_dataType == &quot;number&quot;)
						{
							strDataItem =
String(parseInt(this.dataProvider[i][dataField].toString(),10));
						} 
						else
						{
							strDataItem = this.dataProvider[i][dataField].toString();
						}
						if (strDataItem == strFindItem &amp;&amp; strDataItem.length ==
strFindItem.toString().length)
						{
							this.selectedIndex = i;
	 						if (_toolTipField.length > 0)
							{
								this.toolTip = this.dataProvider[i][_toolTipField]
							}
//							dispatchEvent( new ListEvent( ListEvent.CHANGE ) );
							break;
						}
					}
				}
			}
		}
		
 		override protected function focusOutHandler(event:FocusEvent):void
		{
			super.focusOutHandler(event);
			_typedText = "";
			validateData()
		}
		
		override protected function focusInHandler(event:FocusEvent):void
		{
			this.removeEventListener(KeyboardEvent.KEY_DOWN,this.keyDownHandler);
			super.focusInHandler(event);
			_typedText = "";
			_focusOutTab = false;
		
this.addEventListener(KeyboardEvent.KEY_DOWN,this.keyDownHandler,false,0,true);
		}

		override protected function textInput_changeHandler(event:Event):void
		{
			_typedText += this.textInput.text;
//			trace('_typedText=' + _typedText);
 			if (!findFirstItem(_typedText))
			{
				_typedText = _typedText.substr(0,_typedText.length -1);
				findFirstItem(_typedText);
			}
//			this.dispatchEvent(new Event(Event.CHANGE,true));
		}
		override protected function keyDownHandler(event:KeyboardEvent):void
		{
//			trace("event="+event.toString());
			this.removeEventListener(KeyboardEvent.KEY_DOWN,this.keyDownHandler);
			event.preventDefault();
			if (event.keyCode == Keyboard.TAB)_focusOutTab = true;
			if ((event.keyCode == Keyboard.TAB && _tabOut == null) || event.keyCode
== Keyboard.ENTER) return;
			if (event.keyCode == Keyboard.TAB)
			{
				_tabOut();
			}
 		    if(!event.ctrlKey)
			{
				if (event.keyCode == Keyboard.BACKSPACE || event.keyCode ==
Keyboard.DELETE)
				{
					_typedText = _typedText.substr(0,_typedText.length -1);
					findFirstItem(_typedText);
				}
				if (event.keyCode == Keyboard.DOWN || event.keyCode == Keyboard.RIGHT)
				{
					_typedText = "";
					if (this.dropdown.selectedIndex < this.dataProvider.length - 1)
					{
						this.selectedIndex++;
						this.dropdown.selectedIndex++;
						this.dropdown.scrollToIndex(this.dropdown.selectedIndex);
						_value = this.selectedItem[dataField];
					}
				}
				if (event.keyCode == Keyboard.UP || event.keyCode == Keyboard.LEFT)
				{
					_typedText = "";
					if (this.dropdown.selectedIndex > 0)
					{
						this.selectedIndex--;
						this.dropdown.selectedIndex--;
						this.dropdown.scrollToIndex(this.dropdown.selectedIndex);
						_value = this.selectedItem[dataField];
					}
				}
				if ((event.charCode > 31) && (event.charCode < 128))
				{
					_typedText += String.fromCharCode(event.charCode);
	 				if (!findFirstItem(_typedText))
					{
						_typedText = _typedText.substr(0,_typedText.length -1);
					}
				}
 			}
// 			trace("_typedText=" + _typedText);
		
this.addEventListener(KeyboardEvent.KEY_DOWN,this.keyDownHandler,false,0,true);
//		    super.keyDownHandler(event);
 		}
 		
		private function findFirstItem(strFindItem:String):Boolean
		{
			if (this.dataProvider != null)
			{
				if (strFindItem.length == 0)
				{
					this.selectedIndex = 0;
					this.dropdown.selectedIndex = 0;
					this.dropdown.scrollToIndex(0);
					_value = this.selectedItem[dataField];
					dispatchEvent( new ListEvent( ListEvent.CHANGE ) );
					return true;
				}
				this.dispatchEvent(new MouseEvent("mouseOut"));
				for (var i:int=0;i<this.dataProvider.length;i++)
				{
					if
(this.dataProvider[i][this.labelField].toString().substr(0,strFindItem.length).toUpperCase()
== strFindItem.toUpperCase())
					{
						this.selectedIndex = i;
						this.dropdown.selectedIndex = i;
						this.dropdown.scrollToIndex(i);
						_value = this.selectedItem[dataField];
 						if (_toolTipField.length > 0)
						{
							this.toolTip = this.dataProvider[i][_toolTipField]
							this.dispatchEvent(new MouseEvent("mouseOver"));
						}
						dispatchEvent( new ListEvent( ListEvent.CHANGE ) );
						return true;
					}
				}
			}
			return false;
		}
		
	   	public function killMe():void
		{
			trace('unloading='+this.id);
			this.dataProvider = null;
			this.dropdown.dataProvider = null;
			this.selectedIndex = -1;
			this.selectedItem = null;
			this.value = null;
			callLater(clearEvents);
		}
		
		protected var dctListeners:Dictionary = new Dictionary(); // added
05/22/2018
		protected var bolInClearEvents:Boolean = false;
		
		override public function addEventListener(type:String, listener:Function,
useCapture:Boolean = false, priority:int =
												  0, useWeakReference:Boolean = true):void
		{
			if (bolInClearEvents == false)
			{
				var key:Object = {type: type, useCapture: useCapture};
				if (dctListeners[key])
				{
					removeEventListener(type, dctListeners[key], useCapture);
					dctListeners[key] = null;
				}
				dctListeners[key] = listener;
				super.addEventListener(type, listener, useCapture, priority,
useWeakReference);
			}
		}
		
		public function clearEvents():void
		{
			bolInClearEvents = true;
			try
			{
				for (var key:Object in dctListeners)
				{
					removeEventListener(key.type, dctListeners[key], key.useCapture);
					dctListeners[key] = null;
				}
			}
			catch (e:Error)
			{
				trace('TestBig-clearEvents error='+e.message);
			}
			dctListeners = null;
		}
	

	}
}



--
Sent from: http://apache-flex-users.2333346.n4.nabble.com/