【问题标题】:FLEX: dialog not display immediatelyFLEX:对话框不立即显示
【发布时间】:2009-09-11 11:40:33
【问题描述】:

在 AIR 应用程序中,我有以下代码:

theDialog = PopUpManager.createPopUp( this, TheDialogClass, true ) as TheDialogClass; theDialog.addEventListener(FlexEvent.CREATION_COMPLETE, cpuIntensiveCalc);

在 cpuIntensiveCalc 结束时,对话框被删除。对话框通知用户“有事,请稍候”。

问题是 cpuIntensiveCalc 在对话框绘制之前启动。所以用户体验是应用程序在没有指示符的情况下冻结 10 秒,然后模式对话框在屏幕上快速闪烁(不到一秒)。

Adobe 文档是这么说的 creation_complete

在组件完成构建时调度, 属性处理、测量、布局和绘图。

所以这感觉像是正确的事件。
以完整性的名义,我也尝试过

theDialog = PopUpManager.createPopUp( this, TheDialogClass, true ) as TheDialogClass; cpuIntensiveCalc();

但结果相同。

TIA

【问题讨论】:

  • 哦,cpuIntensiveCalc 没有 UI 更新,全是数学。

标签: apache-flex air


【解决方案1】:

原因是 Flash Player 是单线程的,因此您会阻止 UI 对 Dialog Popup 做出反应,直到数学块完成。

Hacky 修复时间...

你有两个选择。

(这个应该可以工作,但未经测试)将 cpuIntensiveCalc() 调用包装在 callLater 中,以便 UI 可以在您阻止渲染之前完成渲染。

或者

使用“绿色线程”来分解您的处理,这样您就不会完全阻止 UI 处理。 Take a look.

【讨论】:

  • 是的,我试过 callLater,没有骰子。 :|我还尝试使用计时器引入延迟。所以我创建了弹出窗口,然后使用 TimerEvent.TIMER 侦听器启动计时器。这是超级hacky,但我只是想看看它的工作。为了让它工作,我必须有相当高的延迟,比如 250 毫秒。
  • 第二种解决方案对于像 AS3 这样的单线程系统来说是不那么老套的并且可能是最好的解决方案。您还可以尝试主动对象模式,并将计算分解为更小的任务。 en.wikipedia.org/wiki/Active_object
【解决方案2】:

(我只是遇到了同样的问题 => 即使这个帖子很旧,我也只是想贡献我的解决方案)

(免责声明:这有点难看,但他们说在 UI 层没问题... ;-))

Flex 是单线程的(至少从我们开发人员的角度来看,我认为虚拟机使用幕后线程)

=> 您通常在用户对小部件执行某些操作之后在 UI 线程中执行您的代码。任何更新 UI 组件(如 setProgress 或 setLabel)的调用都只会在渲染周期结束时在屏幕上渲染(请参阅 UiComponent 生命周期)。

=> 理论上,在 callLater 中调用“cpuIntensiveCalc”将使框架在执行方法之前显示您的弹出窗口。

但在实践中,我注意到您通常需要几个 UI 循环才能显示弹出窗口,如下所示:

new MuchLaterRunner(popup, 7, cpuIntensiveCalc).runLater();

MuchLaterRunner 的定义如下:

public class MuchLaterRunner
    {
        var uiComp:UIComponent;
        var currentCounter = 0;
        var cyclesToWaitBeforeExecution=0;

        var command:Function;

        public function MuchLaterRunner(uiComp:UIComponent, cyclesToWaitBeforeExecution:uint, command:Function)
        {
            this.uiComp = uiComp;
            this.command = command;
            this.cyclesToWaitBeforeExecution =cyclesToWaitBeforeExecution;
        }

        public function runLater() {

            currentCounter ++;
            if (currentCounter >= cyclesToWaitBeforeExecution) {
                uiComp.callLater(command);
            } else {
                // wait one more cycle...
                uiComp.callLater(runLater);
            }
        }

    }

之后调用 setProgress 的问题也是一样的:我们必须将 cpuIntensiveCalc 划分为可以在每个 UI 周期运行的小的可调用方法,否则进度条不会,err,进度。

【讨论】:

    【解决方案3】:

    在弹出窗口中使用 enterFrame 事件。不要忘记删除 enterFrame 事件处理程序中的侦听器 - 否则将在每个帧中调用 cpu 密集型方法,从而使您的应用程序崩溃。如果一开始这不起作用,请使用私有数字作为计数器并在输入帧处理程序中不断增加它 - 仅当计数器达到适当的值时才调用 cpu heavy 方法。通过跟踪和错误找到“适当的”值。

    theDialog = PopUpManager.createPopUp(this, TheDialogClass, true) as TheDialogClass;
    theDialog.addEventListener(Event.ENTER_FRAME, onEnterFrame);
    private function onEnterFrame(e:Event):void
    {
      //can use theDialog instead of e.currentTarget here.
      (e.currentTarget).removeEventListener(Event.ENTER_FRAME, onEnterFrame);
      cpuIntensiveCalc();
    }
    //in case the above method doesn't work, do it the following way:
    theDialog.addEventListener(Event.ENTER_FRAME, onEnterFrame);
    private var _frameCounter:Number = 0;
    private function onEnterFrame(e:Event):void
    {
      _frameCounter++;
      var desiredCount:Number = 1;//start with one - increment until it works.
      if(_frameCounter < desiredCount)
        return;
      //can use theDialog instead of e.currentTarget here.
      (e.currentTarget).removeEventListener(Event.ENTER_FRAME, onEnterFrame);
      cpuIntensiveCalc();
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-28
      • 2011-09-30
      相关资源
      最近更新 更多