As I said in the comments of my last post about AsyncTokenWrapper I didn’t like the way I was wrapping AsyncToken and handling the response.
A much neater solution to this is to create and register a custom command factory. You register a command based on the return type of your function. In my case I am returning a ProcessingAsyncToken so I go about registering my factory like this:
GlobalFactoryRegistry.instance.messageRouter.addCommandFactory(
ProcessingAsyncToken,
new ProcessingCommandFactory()
);
I do this in a support class that implements ContextBuilderProcessor so that I can set this up when I create my context:
My command factory looks like this:
public class ProcessingCommandFactory implements CommandFactory
{
public function createCommand(
returnValue : Object,
message : Object,
selector : * = null
) : Command
{
return new ProcessingCommand( returnValue,
message,
selector
);
}
}
And just returns a new instance of my ProcessingCommand:
public class ProcessingCommand extends AbstractCommand
{
//-------------------------------------------------
//
// Constructor
//
//-------------------------------------------------
public function ProcessingCommand(
returnValue : *,
message : Object,
selector : *
)
{
super( returnValue, message, selector );
_processingToken = ProcessingAsyncToken( returnValue );
_processingToken.token.addResponder(
new Responder( complete, error )
);
start();
}
//-------------------------------------------------
//
// Private Variables
//
//-------------------------------------------------
private var _processingToken : ProcessingAsyncToken;
//-------------------------------------------------
//
// Overridden Methods: AbstractCommand
//
//-------------------------------------------------
protected override function selectResultValue(
result : *,
targetType : ClassInfo
) : *
{
return ( targetType.getClass() != ResultEvent && result is ResultEvent )
? ResultEvent( result ).result
: result;
}
protected override function selectErrorValue(
result : *,
targetType : ClassInfo
) : *
{
return ( targetType.getClass() == Fault && result is FaultEvent )
? FaultEvent( result ).fault
: result;
}
override protected function complete( result : * = null ) : void
{
var argumentsArray : Array;
if ( _processingToken.resultProcessingFunction != null )
{
try{
argumentsArray = _processingToken.resultProcessingArguments.concat();
argumentsArray.unshift( result.result );
result = _processingToken.resultProcessingFunction.apply(
this,
argumentsArray );
}
catch( e : Error )
{
error( e );
}
}
super.complete( result );
}
override protected function error( result : * = null ) : void
{
var argumentsArray : Array;
if ( _processingToken.faultProcessingFunction != null )
{
argumentsArray = _processingToken.faultProcessingArguments.concat();
argumentsArray.unshift( result.fault );
result = _processingToken.faultProcessingFunction.apply(
this,
argumentsArray );
}
super.error( result );
}
}
We just extend AbstractCommand and override the complete and error functions to apply the functions defined in ProcessingAsyncToken before passing the result on. In the constructor we add a responder to the AsyncToken in the return Value.
I call the function as follows:
[Command( type="com.pricklythistle.picasa.event.ListPicasaAlbumsEvent", messageProperties="userID,kind" )]
public function loadUserAlbums(
userID : String,
kind : String = null
) : ProcessingAsyncToken
{
url = StringUtil.substitute( BASE_URL, userID );
return loadUserEntries( kind );
}
I think this is a much neater solution that wrapping an AsyncToken inside another Async token – that had a really bad smell about it!