RL 1.5 Beginner's trouble
Hi there.
I recently moved from the basic mvc stuff I wrote up myself to RL,
heared alot of good things about it. When trying to mash up some
basic stuff, I encouter a problem saying that a service previously
mapped is null and I have trouble to wrap my head around
this...
So I punshed out a simple MainContext where I define the following stuf:
public class MainContext extends Context implements IContext
{
public function TreeshirtContext(contextView:DisplayObjectContainer)
{
super(contextView);
}
override public function startup():void
{
commandMap.mapEvent(InitEvent.INITIALIZE, MyInitCommand, InitEvent);
injector.mapSingletonOf(IMyService, MyService);
super.startup();
dispatchEvent(new InitEvent(InitEvent.INITIALIZE));
}
}
Then the Init Command, which is being called correctly:
public class MyInitCommand extends Command
{
[Inject]
public var event:MyEvent;
[Inject]
public var service:IMyService;
public function MyInitCommand()
{
service.init(); // here the error is being thrown
}
}
and last but not least:
public class FacebookService extends Actor implements
IFacebookService
{
public function FacebookService()
{
trace("@constructor FacebookService");
super();
}
public function init():void
{
trace("@Service::init()");
}
}
However, I get an error indicating that the service has never
been instantiated. The error is thrown in the Command, hinting that
the service has never been initialized.
What am I missing?
Regards,
Peter
Comments are currently closed for this discussion. You can start a new one.
Keyboard shortcuts
Generic
? | Show this help |
---|---|
ESC | Blurs the current field |
Comment Form
r | Focus the comment reply box |
---|---|
^ + ↩ | Submit the comment |
You can use Command ⌘
instead of Control ^
on Mac
1 Posted by Paul Robertson on 16 Oct, 2012 05:47 AM
The problem is you're calling service.init() in the command's constructor,
which is apparently being called before the service is constructed. In this
case Robotlegs is lazily constructing the service -- not actually creating
it until it's needed -- so the order is something like this:
- command is triggered
- create MyInitCommand instance (call it's constructor) <-- your error here
- Analyze the MyInitCommand for mappings to fulfill
- Identify IMyService mapping, which is mapped but not created yet
- Create IMyService concrete implementation (MyService/FacebookService
instance)
- Inject newly created instance
- call command's execute() method <-- this is where you should do work
In a RL command, your "entry point" is a method named execute(), so rather
than calling service.init() in the command's constructor, you'll want to
create an overridden execute() method and call service.init() there, e.g.:
override public function execute():void
{
service.init();
}
An alternative pattern for initializing services is to use a PostConstruct
method in the service class. When you tag a method with the [PostConstruct]
metatag, that tells Robotlegs to treat the method like a constructor for
the class, only one where all the injections are available. (See above for
why injections aren't available in constructors.) So if you have a method
marked [PostConstruct] the order is something like this:
- some object that has an injection of your service is constructed
- Identify IMyService mapping, which is mapped but not created yet
- Create IMyService concrete implementation (MyService/FacebookService
instance), calling MyService() constructor
- fulfill any injections that the service requires
** Call [PostConstruct] method in service
- Inject newly created service instance where it's needed
- continue doing stuff
Note that while in this example I'm saying to use [PostConstruct] in a
service, you can really use it anywhere. Having said that, I'm pretty sure
I've only ever used it in a service.
Here's an example of what the service class would look like:
public class FacebookService extends Actor implements IFacebookService
{
public function FacebookService()
{
trace("@constructor FacebookService");
super();
}
[PostConstruct]
public function init():void
{
trace("@Service::init()");
}
}
The biggest potential downside to the [PostConstruct] approach is that your
service's init() method isn't called until the service is actually needed
for injection. So for example if your init() method kicks off some
asynchronous process that you'd rather have done at startup rather than
later, you'll definitely want to stick with the init command approach
you're currently using rather than using [PostConstruct]. I've used both
approaches depending on the needs of the app.
Paul
2 Posted by Peter on 16 Oct, 2012 05:39 PM
Oh ofcourse,
override public function execute():void ... is the function supposed to call the service.init() methode. Silly me for not seeing that.
Thanks a bunch for the very detailed answer.
I indeed rather stick to the command approach, most of the stuff I need to accomplish (right now) is basically bootstrapping stuff and go on from there.
Thanks again, best regards,
Peter
Ondina D.F. closed this discussion on 17 Oct, 2012 12:22 PM.