AIR Sqlite:SQLEvent.RESULT没有触发,但语句正在正确执行

问题描述:

好吧,它看起来像我偶然发现奇怪的时间问题...我做了一个快速的SQL包装类执行SQL语句。但是,在调用.execute()之后,SQLEvent.RESULT事件永远不会被触发,但DB中的新条目将按照它的原样创建。真正非常奇怪的是,如果我在调用execute()后立即调用setTimeout(),事件会像预期的那样触发。我希望我在这里错过了一些非常明显的东西......下面是一个示例空气应用程序的链接: http://www.massivepoint.com/airsqltest/AIRSQL.zipAIR Sqlite:SQLEvent.RESULT没有触发,但语句正在正确执行

这里是代码来包装类:

,如果你在第51行中SQLREQUEST类往下看,你会看到注释掉setTimeout()方法。为了使所有的工作,只是取消注释该行..但对我来说这没有任何意义...

任何人有任何想法?我完全难住在这里...

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 

我想你在这里错过的是垃圾收集。

未测试您的代码,但这肯定是问题的根源。

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

参考sqlReq是本地的功能,并成为unreacheable当函数返回。这使得它是可收集的。我想在AIR运行时必须有一些代码,在涉及sql连接时更积极地收集垃圾。因为通常情况下,你不会将ref存储在你的对象中(至少在我的经验中,至少在一个基于web的环境中;这是这样的代码中的一个错误;不过,你只需要在糟糕的一天体验它)。

setTimeout掩盖这个问题(或几乎解决了它,虽然在一个意想不到的方式),因为setTimeout函数内部使用一个Timer。运行计时器不收集。所以,计时器仍然活着并踢,并且对您的SQLRequest实例有一个参考,这使得它可以重新获得,因此不适合收集。如果您的数据库调用需要比超时更长的时间,则会恢复相同的情况。

为了解决这个问题,请将ref存储到对象中,并在完成后妥善处置它。

编辑

另一种选择,如果你不想改变你调用代码的工作方式,是存储裁判实例在类范围(即静态)字典的持续时间这个电话(这个字典并不是使用弱引用键的原因很明显)。

你正在为你的方法增加一个隐藏的副作用,这通常不是一个好设计的标志,但只要你在调用数据库的时候删除它(不管它是否成功),你'很安全,所以我认为问题比其他任何方式都更具风格。

我的意思是这样的:

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]; 
    } 
} 
+0

啊哈废话,就是这样......非常感谢你指出了这一点! – Jake 2010-07-26 03:09:53