AIR Sqlite: SQLEvent.RESULT не запускается, но оператор выполняется правильно - PullRequest
4 голосов
/ 26 июля 2010

Хорошо, похоже, я наткнулся на странную проблему с синхронизацией ... Я сделал быстрый класс-оболочку SQL для выполнения SQL-операторов.Однако после вызова .execute () событие SQLEvent.RESULT никогда не вызывается, но новая запись в БД создается в порядке.Действительно странная часть, если я помещаю setTimeout () сразу после вызова execute (), событие запускается, как и ожидалось ... Надеюсь, я упускаю что-то действительно очевидное ... Вот ссылка на пример приложения air: http://www.massivepoint.com/airsqltest/AIRSQL.zip

А вот код класса оболочки:

Если вы посмотрите на строку 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

1 Ответ

1 голос
/ 26 июля 2010

Я думаю, что вам не хватает здесь сборки мусора.

Не проверял ваш код, но это, безусловно, может быть источником проблемы.

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

СсылкаsqlReq является локальным для функции и становится недоступным, когда функция возвращается.Это делает его коллекционным.Я предполагаю, что во время выполнения AIR должен быть какой-то код, который собирает мусор более агрессивно, когда задействованы соединения SQL.Потому что, как правило, вам не удастся сохранить ссылку на ваш объект (по крайней мере, в веб-среде, по моему опыту; это ошибка в таком коде, тем не менее; вам просто нужно быть в плохой день, чтобы испытать)это).

setTimeout маскирует эту проблему (или почти решает ее, хотя и непреднамеренно), потому что функция setTimeout использует Timer внутри.Запуски таймеров не собираются.Таким образом, таймер активен и работает, и имеет ссылку на ваш экземпляр SQLRequest, что делает его пригодным для повторного использования и, следовательно, недоступным для сбора.Если ваш вызов БД занимает больше времени, чем тайм-аут, вы вернулись в той же ситуации.

Чтобы решить эту проблему, сохраните ссылку на объект и утилизируйте ее, когда закончите.

Редактировать

Другой вариант, если вы не хотите изменять способ работы кода, - сохранить ссылку на экземпляр в словаре с классовой областью (т. Е. Статическом).на время разговора (этот словарь не должен использовать слабые ссылочные ключи по понятным причинам).

Вы добавляете скрытый побочный эффект к своему методу, который не является признаком хорошего дизайна в целом, но до тех пор, пока вы удаляете его, когда завершен вызов в БД (независимо от того, был он успешным или нет)Вы в безопасности, поэтому я думаю, что проблема скорее в стиле, чем в чем-либо еще.

Я имею в виду что-то вроде этого:

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];
    }
}
...