Apache flex FLEX:对话框不会立即显示

Apache flex FLEX:对话框不会立即显示,apache-flex,air,Apache Flex,Air,在AIR应用程序中,我有以下代码: Dialog=PopUpManager.createPopUp(这是DialogClass,true)作为DialogClass; Dialog.addEventListener(FlexEvent.CREATION\u COMPLETE,cpuIntensiveCalc) 在cpuIntensiveCalc结束时,将删除该对话框。该对话框通知用户“发生了一些事情,请待命。” 问题是cpuIntensiveCalc在对话框绘制之前启动。因此,用户体验是,应用程

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

Dialog=PopUpManager.createPopUp(这是DialogClass,true)作为DialogClass; Dialog.addEventListener(FlexEvent.CREATION\u COMPLETE,cpuIntensiveCalc)

在cpuIntensiveCalc结束时,将删除该对话框。该对话框通知用户“发生了一些事情,请待命。”

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

Adobe文档这样说是关于创建的

当组件完成其构造时发送, 特性处理、测量、布局和绘图

因此,这似乎是正确的事件。
以完整性的名义,我也试过了

Dialog=PopUpManager.createPopUp(这是DialogClass,true)作为DialogClass; cpuIntensiveCalc()

但结果是一样的


TIA

原因是Flash播放器是单线程的,因此在数学模块完成之前,您会阻止UI对对话框弹出做出反应

骇客固定时间

你有两个选择

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


使用“绿色线程”中断处理,这样就不会完全阻止UI处理

在弹出窗口中使用enterFrame事件。不要忘记删除enterFrame事件处理程序中的侦听器,否则会在每个帧中调用cpu密集型方法,导致应用程序崩溃。如果这在一开始不起作用,请使用一个专用数字作为计数器,并仅当计数器达到适当的值时,在enterframehandler-callcpu-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();
}
theDialog=PopUpManager.createPopUp(这是DialogClass,true)作为DialogClass;
Dialog.addEventListener(Event.ENTER_FRAME,onEnterFrame);
私有函数onEnterFrame(e:事件):void
{
//可以在此处使用Dialog而不是e.currentTarget。
(e.currentTarget).removeEventListener(Event.ENTER_FRAME,onEnterFrame);
cpuIntensiveCalc();
}
//如果上述方法不起作用,请按以下方法进行:
Dialog.addEventListener(Event.ENTER_FRAME,onEnterFrame);
私有变量_frameCounter:Number=0;
私有函数onEnterFrame(e:事件):void
{
_帧计数器++;
var desiredCount:Number=1;//从一个增量开始,直到它工作为止。
if(_frameCounter
(我刚刚遇到了同样的问题=>即使这个线程很旧,我也只想贡献我的解决方案)

(免责声明:这有点难看,但他们说在UI层这没关系…;-))

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

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

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

但实际上,我注意到,在弹出窗口显示之前,您通常需要进行几个UI循环,如下所示:

new MuchLaterRunner(popup, 7, cpuIntensiveCalc).runLater();
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);
            }
        }

    }
MuchLaterRunner的定义如下:

new MuchLaterRunner(popup, 7, cpuIntensiveCalc).runLater();
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周期运行的小的可调用方法,否则progressbar将不会,呃,前进

哦,而且cpuIntensiveCalc没有UI更新,全是数学。是的,我后来试过打电话,没有骰子我还尝试使用计时器引入延迟。因此,我创建了弹出窗口,然后用TimerEvent.timer侦听器启动计时器。这是超级黑客,但我只是想看到它的工作。为了让它工作,我必须有相当高的延迟,比如250ms。第二个解决方案是不太粗糙的,而且对于像AS3这样的单线程系统来说可能是最好的解决方案。您还可以尝试使用活动对象模式,并将计算分解为更小的任务。