使用演示模型模式的 Flex 4 的 Parsley 依赖注入问题
我有一个视图类 EmployeeList 如下:
<?xml version="1.0" encoding="utf-8"?>
<s:NavigatorContent xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:parsley="http://www.spicefactory.org/parsley"
xmlns:mx="library://ns.adobe.com/flex/mx" width="400" height="300">
<fx:Script>
<![CDATA[
import cafeparsley.model.EmployeeListPM;
[Inject]
[Bindable]
public var model : EmployeeListPM;
[Init]
public function init () : void {
model.init();
}
]]>
</fx:Script>
<s:Panel title="Employee List" horizontalCenter="0">
<s:HGroup paddingTop="50">
<s:Button label="Add New Employee" click="model.addNewEmployee()" />
<mx:Spacer width="100%" />
<s:Button label="Logout" click="model.logout()" />
<mx:Spacer width="100%" height="20" />
</s:HGroup>
<s:List id="empList" dataProvider="{ model.employees }" labelFunction="model.properName"
change="model.initUpdateEmployee(empList.selectedItem);empList.selectedIndex = -1;" width="100%" />
<s:Label id="error" color="0xFF0000" />
</s:Panel>
</s:NavigatorContent>
PM 看起来像这样:
package cafeparsley.model
{
import cafeparsley.events.EmployeeEvent;
import cafeparsley.events.NavigationEvent;
import cafeparsley.services.impl.EmployeeServiceImpl;
import cafeparsley.vo.Employee;
import flash.events.EventDispatcher;
import mx.collections.ArrayCollection;
import mx.rpc.IResponder;
[Bindable]
[Event(name="navigationEvent", type="cafeparsley.events.NavigationEvent")]
[ManagedEvents("navigationEvent")]
public class EmployeeListPM extends EventDispatcher implements IResponder
{
public var employeeService : EmployeeServiceImpl = new EmployeeServiceImpl();
public var employees : ArrayCollection;
public function init() : void
{
loadEmployees();
}
public function EmployeeListPM()
{
}
public function loadEmployees():void
{
employeeService.loadEmployees( this );
}
无论我使用还是自动装配来执行注入,当我运行它时,我都会收到以下错误消息:
TypeError: Error #1009: Cannot access a property or method空对象引用。 在 Cafeparsley.view::EmployeeList/_EmployeeList_List1_i()[C:\dev\code\workspace\Examples\CafeParsley\src\cafeparsley\view\EmployeeList.mxml:29] 在 Cafeparsley.view::EmployeeList/_EmployeeList_Array2_c() 在 mx.core::DeferredInstanceFromFunction/getInstance()[E:\dev\4.x\frameworks\projects\framework\src\mx\core\DeferredInstanceFromFunction.as:105] 在spark.components::SkinnableContainer/createDeferredContent()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\SkinnableContainer.as:985] 在spark.components::SkinnableContainer/createContentIfNeeded()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\SkinnableContainer.as:1014] 在spark.components::SkinnableContainer/createChildren()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\SkinnableContainer.as:827] 在 mx.core::UIComponent/initialize()[E:\dev\4.x\frameworks\projects\framework\src\mx\core\UIComponent.as:7349] 在 mx.core::UIComponent/http://www.adobe.com/2006/flex/mx/internal::childAdded()[E:\dev\4.x\frameworks\projects\framework\src\mx\核心\UIComponent.as:7241] 在 mx.core::UIComponent/addChildAt()[E:\dev\4.x\frameworks\projects\framework\src\mx\core\UIComponent.as:6947] 在spark.components::Group/addDisplayObjectToDisplayList()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\Group.as:1825] 在spark.components::Group/http://www.adobe.com/2006/flex/mx/internal::elementAdded()[E:\dev\4.x\frameworks\projects\spark\src\spark\组件\Group.as:1416] 在spark.components::Group/setMXMLContent()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\Group.as:512] 在spark.components::Group/set mxmlContent()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\Group.as:452] 在spark.components::SkinnableContainer/set mxmlContent()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\SkinnableContainer.as:604] 在spark.components::SkinnableContainer/createDeferredContent()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\SkinnableContainer.as:986] 在spark.components::SkinnableContainer/createContentIfNeeded()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\SkinnableContainer.as:1014] 在spark.components::SkinnableContainer/createChildren()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\SkinnableContainer.as:827] 在spark.components::NavigatorContent/createChildren()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\NavigatorContent.as:225] 在 mx.core::UIComponent/initialize()[E:\dev\4.x\frameworks\projects\framework\src\mx\core\UIComponent.as:7349] 在 Cafeparsley.view::EmployeeList/initialize()
因此,当抛出错误时,employeeListPM 为 null。但是如果我注释掉
组件,重新运行并在 init 方法中设置断点,init() 将被调用。所以并不是我的上下文配置错误,只是PM没有及时注入而抛出了错误。但根据 Parsley 手册,如果我使用自动装配或
,PM 应该在需要时注入。
在我认为相对简单的依赖注入场景中,我看不出我做错了什么。你能帮忙吗?
I have a View class EmployeeList as follows:
<?xml version="1.0" encoding="utf-8"?>
<s:NavigatorContent xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:parsley="http://www.spicefactory.org/parsley"
xmlns:mx="library://ns.adobe.com/flex/mx" width="400" height="300">
<fx:Script>
<![CDATA[
import cafeparsley.model.EmployeeListPM;
[Inject]
[Bindable]
public var model : EmployeeListPM;
[Init]
public function init () : void {
model.init();
}
]]>
</fx:Script>
<s:Panel title="Employee List" horizontalCenter="0">
<s:HGroup paddingTop="50">
<s:Button label="Add New Employee" click="model.addNewEmployee()" />
<mx:Spacer width="100%" />
<s:Button label="Logout" click="model.logout()" />
<mx:Spacer width="100%" height="20" />
</s:HGroup>
<s:List id="empList" dataProvider="{ model.employees }" labelFunction="model.properName"
change="model.initUpdateEmployee(empList.selectedItem);empList.selectedIndex = -1;" width="100%" />
<s:Label id="error" color="0xFF0000" />
</s:Panel>
</s:NavigatorContent>
The PM looks like this:
package cafeparsley.model
{
import cafeparsley.events.EmployeeEvent;
import cafeparsley.events.NavigationEvent;
import cafeparsley.services.impl.EmployeeServiceImpl;
import cafeparsley.vo.Employee;
import flash.events.EventDispatcher;
import mx.collections.ArrayCollection;
import mx.rpc.IResponder;
[Bindable]
[Event(name="navigationEvent", type="cafeparsley.events.NavigationEvent")]
[ManagedEvents("navigationEvent")]
public class EmployeeListPM extends EventDispatcher implements IResponder
{
public var employeeService : EmployeeServiceImpl = new EmployeeServiceImpl();
public var employees : ArrayCollection;
public function init() : void
{
loadEmployees();
}
public function EmployeeListPM()
{
}
public function loadEmployees():void
{
employeeService.loadEmployees( this );
}
Regardless of whether I use or autowiring to perform injection, when I run this I get a the following error message:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at cafeparsley.view::EmployeeList/_EmployeeList_List1_i()[C:\dev\code\workspace\Examples\CafeParsley\src\cafeparsley\view\EmployeeList.mxml:29]
at cafeparsley.view::EmployeeList/_EmployeeList_Array2_c()
at mx.core::DeferredInstanceFromFunction/getInstance()[E:\dev\4.x\frameworks\projects\framework\src\mx\core\DeferredInstanceFromFunction.as:105]
at spark.components::SkinnableContainer/createDeferredContent()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\SkinnableContainer.as:985]
at spark.components::SkinnableContainer/createContentIfNeeded()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\SkinnableContainer.as:1014]
at spark.components::SkinnableContainer/createChildren()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\SkinnableContainer.as:827]
at mx.core::UIComponent/initialize()[E:\dev\4.x\frameworks\projects\framework\src\mx\core\UIComponent.as:7349]
at mx.core::UIComponent/http://www.adobe.com/2006/flex/mx/internal::childAdded()[E:\dev\4.x\frameworks\projects\framework\src\mx\core\UIComponent.as:7241]
at mx.core::UIComponent/addChildAt()[E:\dev\4.x\frameworks\projects\framework\src\mx\core\UIComponent.as:6947]
at spark.components::Group/addDisplayObjectToDisplayList()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\Group.as:1825]
at spark.components::Group/http://www.adobe.com/2006/flex/mx/internal::elementAdded()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\Group.as:1416]
at spark.components::Group/setMXMLContent()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\Group.as:512]
at spark.components::Group/set mxmlContent()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\Group.as:452]
at spark.components::SkinnableContainer/set mxmlContent()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\SkinnableContainer.as:604]
at spark.components::SkinnableContainer/createDeferredContent()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\SkinnableContainer.as:986]
at spark.components::SkinnableContainer/createContentIfNeeded()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\SkinnableContainer.as:1014]
at spark.components::SkinnableContainer/createChildren()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\SkinnableContainer.as:827]
at spark.components::NavigatorContent/createChildren()[E:\dev\4.x\frameworks\projects\spark\src\spark\components\NavigatorContent.as:225]
at mx.core::UIComponent/initialize()[E:\dev\4.x\frameworks\projects\framework\src\mx\core\UIComponent.as:7349]
at cafeparsley.view::EmployeeList/initialize()
So the employeeListPM is null when the error is thrown. However if I comment out the<s:List>
component, rerun and set a breakpoint in the init method, init() will get called. So it's not that my context config is wrong, it's just that the PM hasn't been injected in time and the error is thrown. But according to the Parsley manual if I use autowiring or <parsley:configure/>
the PM should be injected by the time it is needed.
I can't see what is I am doing wrong in what I thought was a relatively trivial dependency injection scenario. Can you help?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这里有几点:
您的示例不包含
或
标签,但是因为您在帖子中提到了它们我假设它们只是示例代码中缺失的。 (如果没有,那么您需要添加其中之一才能使其工作)。但是,更有可能的是,您的代码中存在竞争条件。
具体来说,这些行:
Model
是一个注入属性,但不能保证在代码首次运行时已注入。相反,将代码移动到执行空检查的类中的脚本中,然后将逻辑推迟回 PM。
IE:
A couple of points here:
Your example doesn't include the
<Configure />
or<FastInject />
tags, however since you mention them in your post I'll assume that they're just missing from the sample code. (If not, then you need to add one of these for this to work).However, more likely, you have race conditions in your code.
Specifically, these lines:
Model
is an injected property, however it's not guaranteed to have been injected at the time that the code is first run.Instead, move the code into script within the class which performs a null check, and then defers logic back to the PM.
ie:
另一件需要考虑的事情是,您正在从标有 Parsley [Init] 元标记的 View 函数调用 model.init() 。我建议您将相同的 [Init] 元标记应用于模型的 init() 方法。
这样做而不是从视图中调用 model.init() 。尽管生命周期文档指出:
我得到了更加一致的结果,没有直接调用注入对象之间的任何 init() 方法,而是利用元数据标记方法。
Another thing to consider is that you are calling model.init() from the View's function marked with the Parsley [Init] metatag. I would suggest that you apply the same [Init] metatag to the init() method of the Model.
Do this rather than calling model.init() from the view. Altho the Lifecycle documentation states:
I've had much more consistent results not calling any init() methods between injected objects directly but rather utilizing the metadata tag approach.