Performance Adobe AIR Scrolling在iPad上的性能(2)-我能期待什么?

Performance Adobe AIR Scrolling在iPad上的性能(2)-我能期待什么?,performance,actionscript-3,apache-flex,ipad,air,Performance,Actionscript 3,Apache Flex,Ipad,Air,我目前正在开发一个AdobeAIR应用程序,该应用程序以iPad2为硬件平台,无法在其中一个屏幕上获得良好的滚动性能。我使用的是一个spark列表,带有如下自定义项目渲染器: <s:List id="productList" top="116" bottom="0" left="10" right="10" width="100%" visible="true" includeInLayout="true" height="0" maxHeight="50

我目前正在开发一个AdobeAIR应用程序,该应用程序以iPad2为硬件平台,无法在其中一个屏幕上获得良好的滚动性能。我使用的是一个spark列表,带有如下自定义项目渲染器:

<s:List id="productList" top="116" bottom="0" left="10" right="10" 
    width="100%"
    visible="true" includeInLayout="true"
    height="0"
    maxHeight="500"
    opaqueBackground="#ffffff"
    itemRenderer="myRenderer">
</s:List>
正如您所看到的,这是相当轻的重量,但我的数据提供程序包含100个以上的项目,其中11个项目可以在任何时候出现在屏幕上。我所读到的关于提高滚动性能的所有内容都是围绕使用
opaqueBackground
cacheAsBitmap
展开的,但是无论我尝试了什么,这里都没有帮助。在列表级别使用
cacheAsBitmap
没有任何帮助,因为一旦您滚动了超过两行需要重新渲染整个内容时,项目渲染器循环就会启动,当快速滚动时,在项目渲染器级别使用它的速度仍然非常慢——可能是因为在非常快速的滚动过程中,许多项目同时被回收


我知道iPad在一帧中以60 fps的速度快速播放一屏信息应该没有问题,但当我快速滚动时,我发现它很难以10 fps的速度播放(从视线中)。因此,问题是:我是否错过了一些明显的东西,或者这是由于使用AIR时涉及的层数(和矢量渲染)导致的吗?对于记录,我已尝试更改应用程序的渲染模式,并尝试更改帧速率以消除明显的问题

这有点猜测,但是itemRenderer可以优化吗?是否每次重绘组件时都需要对所有子级进行定位和调整大小?是否需要在每次commitProperties运行时更新productName.text

以下是我如何修改内容:

import mx.controls.listClasses.IListItemRenderer;
import mx.core.UIComponent;
import mx.events.FlexEvent;
import mx.utils.ColorUtil;

import spark.components.Label;
import spark.components.TextInput;

public final class OrderViewProductLineTestIR extends UIComponent implements IListItemRenderer 
{
    public function OrderViewProductLineTestIR()
    {
        super();
    }

    // Internal variable for the property value.

private var _data:Object;

// Add a dataChanged property 
private var dataChanged :Boolean = false

private var productName:Label;
private var orderQty:TextInput;
private var stockQty:TextInput;


// Make the data property bindable.
[Bindable("dataChange")]

// Define the getter method.
public function get data():Object
{
    return _data;
}

// Define the setter method, and dispatch an event when the property
// changes to support data binding.
public function set data(value:Object):void
{
    _data = value;
    // switch the dataChanged flag 
    dataChanged = true;
    invalidateProperties();
    dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
}

override protected function createChildren():void
{
    super.createChildren();

    productName = new Label();
    // productName.visible = true;
    addChild(productName);

    orderQty = new TextInput();
    addChild(orderQty);

    stockQty = new TextInput();
    addChild(stockQty);

}

override protected function commitProperties():void
{
    super.commitProperties();
    // Only update the display if the data actually changed 
    If(dataChanged){
      productName.text = _data.Name;
      dataChanged = false;
    }
}


// add variable to tell whether the component's children have been sized and positioned or not
// since they have static locations, no need to set these each time
protected var compChildrenSized :Boolean = false;
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
    super.updateDisplayList(unscaledWidth, unscaledHeight);
    if(!compChildrenSized){
     productName.move(0, 0);
     productName.setActualSize(250, 48);

     orderQty.move(270, 0);
     orderQty.setActualSize(100, 48);

     stockQty.move(390, 0);
     stockQty.setActualSize(100, 48);

     compChildrenSized = true;
    }
}

override protected function measure():void
{
    super.measure();

    measuredWidth = 490;
    measuredHeight = 48; 
}
}
我想我会补充一点,我不确定这项措施是否会实施。如果将textInputs替换为标签,会发生什么情况?您使用的是Flex4.6吗?如果是,您使用的是StyleableStageText(又名StageText)还是使用StyleableTextField的4.5皮肤?我想知道StageText滚动是否会扼杀性能,因为它挂在Flash显示列表的上方

如果完全删除textInput并替换为标签,会发生什么情况

这些都是小事,我不确定它们是否有用

在你的“火花列表组件”上试试这个
1/添加布局(水平或垂直,取决于所需内容;)
2/在列表组件上添加属性“useVirtualLayout=true”

告诉我结果是什么。。。但我认为它会更平滑(非常平滑), 因为当您将元素添加到列表中时,所有组件都会呈现,即使 他们在布局之外。。。因此,使用“useVirtualLayout”只渲染视口中的项目,其他项目则被销毁。。。

再见!享受Flash Builder带来的乐趣!拥有一个多支持应用程序是一项非常酷的技术

有点晚了。但是

的确,如果你想要接近本地性能的东西,最好使用椋鸟和羽毛

但您仍然可以优化渲染器。 请不要在Flex mobile应用程序中的任何位置使用绑定。 扩展UIComponent是正确的做法。 我认为最好不要使用invalidate并在数据设置器中设置属性


希望能有所帮助。

有一件事你可能想试试。在您的情况下,看起来不需要从覆盖中调用super。老实说,虽然你不会从Spark列表中获得本地性能。如果您有足够的灵活性,您可能需要签出foxhole GPU组件:。而不是cacheAsBitmap,对于移动设备,您需要cacheAsBitmapMatrix。看见但即便如此。。。我经常提醒人们flash虚拟机非常糟糕。史蒂夫·乔布斯不想在他的设备上安装它是有原因的。我不想在这里挑起粉丝大战,我不是苹果或flash的粉丝,我只是在说实话。Adobe在LLVM.org上发布了一个基准测试,显示AS3的性能大约是原生C的1%,并且随着LLVM优化(偶尔)达到30%的峰值。另外,我很好奇您构建的AIR版本是什么。请参阅下面的帖子,它可能对您有所帮助。我尝试使用标识矩阵缓存AsBitMapMatrix,不幸的是,由于某种原因,它导致图像模糊-看起来渲染到的多边形没有与视图端口1:1映射。我怀疑这只是AdobeBloat杀死它的一个例子:(我使用的是AIR3.2和Flex4。6@shaunhusain你漏掉了一个词:)从我读到的UIComponent是最轻的扩展基础…尝试了上述方法,但没有效果,虽然代码显然更为优化,但我认为瓶颈在堆栈的更底层——很可能就在Adobe下面的代码层中。谢谢你的支持,谢谢。虽然有点问题,但没有什么不同,很确定它已经在回收电池了。真不明白这样一个强大的设备怎么能像这样跪下来!
import mx.controls.listClasses.IListItemRenderer;
import mx.core.UIComponent;
import mx.events.FlexEvent;
import mx.utils.ColorUtil;

import spark.components.Label;
import spark.components.TextInput;

public final class OrderViewProductLineTestIR extends UIComponent implements IListItemRenderer 
{
    public function OrderViewProductLineTestIR()
    {
        super();
    }

    // Internal variable for the property value.

private var _data:Object;

// Add a dataChanged property 
private var dataChanged :Boolean = false

private var productName:Label;
private var orderQty:TextInput;
private var stockQty:TextInput;


// Make the data property bindable.
[Bindable("dataChange")]

// Define the getter method.
public function get data():Object
{
    return _data;
}

// Define the setter method, and dispatch an event when the property
// changes to support data binding.
public function set data(value:Object):void
{
    _data = value;
    // switch the dataChanged flag 
    dataChanged = true;
    invalidateProperties();
    dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
}

override protected function createChildren():void
{
    super.createChildren();

    productName = new Label();
    // productName.visible = true;
    addChild(productName);

    orderQty = new TextInput();
    addChild(orderQty);

    stockQty = new TextInput();
    addChild(stockQty);

}

override protected function commitProperties():void
{
    super.commitProperties();
    // Only update the display if the data actually changed 
    If(dataChanged){
      productName.text = _data.Name;
      dataChanged = false;
    }
}


// add variable to tell whether the component's children have been sized and positioned or not
// since they have static locations, no need to set these each time
protected var compChildrenSized :Boolean = false;
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
    super.updateDisplayList(unscaledWidth, unscaledHeight);
    if(!compChildrenSized){
     productName.move(0, 0);
     productName.setActualSize(250, 48);

     orderQty.move(270, 0);
     orderQty.setActualSize(100, 48);

     stockQty.move(390, 0);
     stockQty.setActualSize(100, 48);

     compChildrenSized = true;
    }
}

override protected function measure():void
{
    super.measure();

    measuredWidth = 490;
    measuredHeight = 48; 
}
}