AIR Sqlite: SQLEvent.RESULT does not fire, but the statement is executed correctly

Well, it looks like I came across a strange synchronization problem ... I made a quick SQL shell class to execute SQL statements. However, after calling the .execute () function, the SQLEvent.RESULT event never fires, but a new record in the database is created, as it should be. Actually the very strange part is, if I put setTimeout () right after calling execute (), the event fires as expected. Hope I'm missing something really obvious here ... Here is a link to an example application for air: http://www.massivepoint.com/airsqltest/AIRSQL.zip

And here is the code for the wrapper class:

if you look at line 51 in the SQLRequest class, you will see a commented out setTimeout () method. For everything to work, just uncomment this line .. but for me it makes no sense ...

Anyone have any thoughts? I'm here completely here ...

package com.jac.sqlite {//Package import flash.data.SQLConnection; import flash.data.SQLStatement; import flash.events.EventDispatcher; import flash.events.SQLErrorEvent; import flash.events.SQLEvent; import flash.utils.setTimeout; public class SQLRequest extends EventDispatcher {//SQLRequest Class private var _callback:Function; private var _dbConn:SQLConnection; private var _query:String; private var _params:Object; private var _statement:SQLStatement; public function SQLRequest(callback:Function, connection:SQLConnection, query:String, parameters:Object=null):void {//SQLRequest trace("Creating new SQL Request"); _callback = callback; _dbConn = connection; _query = query; _params = parameters; _statement = new SQLStatement(); _statement.sqlConnection = _dbConn; _statement.text = _query; if (_params != null) {//assign for (var param:String in _params) {//params trace("Setting Param: " + param + " to: " + _params[param]); _statement.parameters[param] = _params[param]; }//params }//assign //setup events _statement.addEventListener(SQLEvent.RESULT, handleResult, false, 0, true); _statement.addEventListener(SQLErrorEvent.ERROR, handleError, false, 0, true); }//SQLRequest public function startLoad():void {//execute _statement.execute(); //setTimeout(handleTimeOut, 10000); }//execute //TEMP private function handleTimeOut():void {//handleTimeOut trace("Executing: " + _statement.executing + " / " + executing); }//handleTimeOut private function handleResult(e:SQLEvent):void {//handleResult trace("Good SQL Request"); _callback(e); dispatchEvent(e); }//handleResult private function handleError(e:SQLErrorEvent):void {//handleError trace("SQL Error: " + e.errorID + ": " + e.error); //dispatchEvent(e); }//handleError public function get executing():Boolean {//get executing return _statement.executing; }//get executing public function get query():String { return _query; } public function get statement():SQLStatement { return _statement; } }//SQLRequest Class }//Package 
+4
source share
1 answer

I think you are missing out on garbage collection here.

Did not check your code, but this can certainly be the source of the problem.

 var sqlReq:SQLRequest = new SQLRequest(handleResult, _dbConn, sql); sqlReq.startLoad(); 

The sqlReq reference is local to the function and becomes inaccessible when the function returns. This makes it collectible. I assume that there should be some code in the AIR runtime that collects garbage more aggressively when there are sql connections associated with it. Because, as a rule, you will get rid of not having to store a link to your object (at least in a web environment, in my experience, this is a mistake in such code, however, you just need to be on a bad day, to experience it).

setTimeout masks this problem (or almost solves it, albeit inadvertently), because the setTimeout function uses Timer internally. Timers do not start. Thus, the timer is alive and kicking and has a link to your instance of SQLRequest , which makes it reusable, and therefore it cannot be read for collection. If your DB call takes longer than the wait time, you are in the same situation again.

To solve this problem, keep a reference to the object and delete it correctly when done.

Edit

Another option, if you do not want to change the way the code works, stores the ref in the instance in the dictionary with the class (i.e., static) for the entire duration of the call (this shoul dictionary does not use weak reference keys for obvious reasons).

You add a hidden side effect to your method, which is not a sign of good design in general, but as long as you delete it when the call to the database is completed (whether it was done or not) is safe, so I think that the problem is more in style than in anything else.

What I mean is something like this:

 private static var _dict:Dictionary = new Dictionary(); public function startLoad():void {//execute _statement.execute(); // add a self reference to dict so the instance won't be collected // do this in the last line, so if we have an exception in execute, this // code will not run (or add a try/catch if you want, but this is simpler // and cleaner, IMO addToDict(); }//execute private function handleResult(e:SQLEvent):void {//handleResult // remove the self reference before running any other code // (again, this is in case the code that follows throws) removeFromDict(); trace("Good SQL Request"); _callback(e); dispatchEvent(e); }//handleResult private function handleError(e:SQLErrorEvent):void {//handleError // same comment as handleResult removeFromDict(); trace("SQL Error: " + e.errorID + ": " + e.error); //dispatchEvent(e); }//handleError private function addToDict():void { _dict[this] = true; } private function removeFromDict():void { if(_dict[this]) { delete _dict[this]; } } 
+1
source

All Articles