Spark SkinnableComponent 皮肤销毁策略

发布于 2024-12-15 13:54:19 字数 1609 浏览 0 评论 0原文

作为尝试解决应用程序内存泄漏问题的一部分,我们发现对于每个 SkinnableComponentskinDestructionPolicy 都设置为 “never”默认情况下。

这意味着当使用静态皮肤部件时,皮肤将永远保留在内存中。
此外,主机组件中对partRemoved()的重写永远不会被触发。 因此,我们在 partAdded() 重写中添加的事件侦听器不会被删除,这实际上会导致视图和皮肤保留在内存中。

当进行大量视图切换时,这是不可接受的。

以下是我们现在如何解决此问题的示例:

public class ViewA extends SkinnableComponent
{
    [SkinPart(required = "true")]
    public var labelA:Label;

    [SkinPart(required = "true")]
    public var buttonA:Button;

    public function ViewA()
    {
        super();
        mx_internal::skinDestructionPolicy = 'auto';
    }

    override protected function getCurrentSkinState():String
    {
        return super.getCurrentSkinState();
    }

    override protected function partAdded(partName:String, instance:Object):void
    {
        super.partAdded(partName, instance);

        trace("ViewA::partAdded " + partName);

        if (instance == buttonA)
        {
            buttonA.addEventListener(MouseEvent.CLICK, buttonClickedHandler);
        }
    }

    override protected function partRemoved(partName:String, instance:Object):void
    {


        trace("ViewA::partRemoved " + partName);

        if (instance == buttonA)
        {
            buttonA.removeEventListener(MouseEvent.CLICK, buttonClickedHandler);
        }

        super.partRemoved(partName, instance);
    }

    override public function stylesInitialized():void
    {
        setStyle("skinClass", ViewASkin);
    }
}

但是,使用 mx::internal 方法来规避此行为对我来说似乎相当奇怪。 有关这方面的文档也很少,因此任何想法都将受到欢迎。

干杯

As a part of trying to tackle a memory leak in our application, we discovered that for every SkinnableComponent, the skinDestructionPolicy is set to "never" by default.

This means that when using static skin parts, the skin is forever detained in memory.
Furthermore, the override of a partRemoved() in the host component will never be triggered.
Hence, event listeners we add in the partAdded() override are not removed, which effectively causes views and skins to be kept in memory.

When doing a lot of view switches this is just not acceptable.

Here is an example of of how we are working around this now:

public class ViewA extends SkinnableComponent
{
    [SkinPart(required = "true")]
    public var labelA:Label;

    [SkinPart(required = "true")]
    public var buttonA:Button;

    public function ViewA()
    {
        super();
        mx_internal::skinDestructionPolicy = 'auto';
    }

    override protected function getCurrentSkinState():String
    {
        return super.getCurrentSkinState();
    }

    override protected function partAdded(partName:String, instance:Object):void
    {
        super.partAdded(partName, instance);

        trace("ViewA::partAdded " + partName);

        if (instance == buttonA)
        {
            buttonA.addEventListener(MouseEvent.CLICK, buttonClickedHandler);
        }
    }

    override protected function partRemoved(partName:String, instance:Object):void
    {


        trace("ViewA::partRemoved " + partName);

        if (instance == buttonA)
        {
            buttonA.removeEventListener(MouseEvent.CLICK, buttonClickedHandler);
        }

        super.partRemoved(partName, instance);
    }

    override public function stylesInitialized():void
    {
        setStyle("skinClass", ViewASkin);
    }
}

However, using the mx::internal way to circumvent this behavior seems rather odd to me.
Documentation about this is scarce as well, so any ideas will be very welcome.

Cheers

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

も星光 2024-12-22 13:54:19

根据我的经验,在 Flex SDK 中使用 mx::internal 命名空间通常意味着以下内容:“您可以使用此功能,如果您知道自己要做什么的话正在做的事情,而且我们(Adobe,或未来的 Apache 社区)也不保证这个 API 在 Flex 的未来版本中永远不会改变”。

因此,除非您非常关心向后兼容性,否则它的使用并没有真正的问题。如果您确实想避免使用它,您始终可以在子类中实现 skinDestructionPolicy="auto" 的行为。不需要编写太多代码:

    override public function initialize():void {
        addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
        addEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler);

        super.initialize();
    }

    private function addedToStageHandler(event:Event):void {
        if (skin == null) attachSkin();
    }

    private function removedFromStageHandler(event:Event):void {
        detachSkin();
    }

请注意,在 SkinnableComponent 类中,这两个事件侦听器在 commitProperties() 方法中附加(或不附加,具体取决于策略)。我将其移至 initialize() 方法,因为我们不再需要检查 skinDestructionPolicy 属性中的更改。

另请注意,如果同时将 mx::internal SkinDestructionPolicy 设置为 “auto”,则此解决方案可能会导致错误。

In my experience the usage of the mx::internal namespace in the Flex SDK usually means something along the lines of: "you can use this functionality, if you know what you're doing, and also we (Adobe, or the Apache community in the future) don't guarantee that this API will never change in future versions of Flex".

So there's no real issue with its usage, unless you're very concerned with backwards compatibility. If you really want to avoid using it, you can always just implement the behavior of skinDestructionPolicy="auto" in your subclass. There's not that much code to write:

    override public function initialize():void {
        addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
        addEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler);

        super.initialize();
    }

    private function addedToStageHandler(event:Event):void {
        if (skin == null) attachSkin();
    }

    private function removedFromStageHandler(event:Event):void {
        detachSkin();
    }

Note that in the SkinnableComponent class these two event listeners are attached (or not, depending on the policy) in the commitProperties() method. I moved that to the initialize() method because we don't need to check for changes in the skinDestructionPolicy property anymore.

Also note that this solution might cause an error if one did set mx::internal skinDestructionPolicy to "auto" alongside.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文