如何在Flex中显示FileStream的保存进度?

时间:2013-07-04 20:01:09

标签: actionscript-3 flex file-io asynchronous progress

我正在制作一个简单的工具,让用户最终将图像保存到磁盘。 为此,我使用FileStream类及其writeBytes()方法。

这很有效。当我尝试使用简单的mx:ProgressBar显示保存进度时,会出现问题。我尝试了一些方法,但似乎都没有。

这是ActionScript的一段代码:

private function save(file:File, image:MyImageClass):void {
    var data:BitmapData = new BitmapData(width, height, true, 0x000000);
    image.draw(data, _cols);
    var bytes:ByteArray = new PNGEncoder().encode(data);
    fileStream = new FileStream();
    fileStream.addEventListener(OutputProgressEvent.OUTPUT_PROGRESS, onProgress);
    fileStream.addEventListener(Event.CLOSE, onClose);
    try {
        fileStream.openAsync(file, FileMode.WRITE);
        fileStream.writeBytes(bytes);
    } catch (e:Error) {
        Alert.show("Error trying to save the image: " + e.message);
    } finally {
        fileStream.close();
    }
}

private function onProgress(event:OutputProgressEvent):void {
    var progressRatio:Number = (1 - (event.bytesPending / event.bytesTotal));
    progressBar.setProgress(progressRatio, 1);
    trace(progressRatio);
    if (event.bytesPending == 0)
        event.target.close();
}

private function onClose(event:Event):void {
    trace("closed");
}

进度条的mxml:

<mx:ProgressBar id="progressBar" mode="manual"/>

执行此操作时,我获得了一个冻结的界面,该界面在文件完全保存时释放,并且在控制台上我同时获得所有跟踪。进度条保持在0%,直到界面未经过冷却,并且达到100%。

我知道Flash是单线程,但我认为FileStream.openAsync()方法应该做脏工作以使我的界面负责。做这个简单的(我认为)常见任务应该不难。

问题是:我做错了什么?

提前致谢

3 个答案:

答案 0 :(得分:3)

文件保存多大?

在保存文件方面,您的代码似乎很好。但是,我怀疑实际上花了很长时间才将文件编码为PNG格式。不幸的是,PNGEncoder不会发送任何进度事件。但是你应该查看这个project from Lee Burrows,或者考虑使用Actionscript Workers在另一个线程中进行编码。

快速证明它的方法:在编码为PNG之前/之后添加跟踪语句。大延迟是对应于此阶段还是实际保存?

如果这没有帮助,请指定文件的大小,以及是否收到0,1或多个OUTPUT_PROGRESS事件。

答案 1 :(得分:1)

我同意Sunil,但我想补充一两件事。

首先,我建议使用BitmapData类的新方法对图像进行编码,因为它更快更容易。所以你的代码会变成这样的东西:

var data:BitmapData = new BitmapData(width, height, true, 0x000000);
image.draw(data, _cols);
var bytes:ByteArray = data.encode(data.rect, new PNGEncoderOptions());

您可以跟踪写入文件的进度(虽然我怀疑这并不需要太多时间,如Sunil所说),如下所示:

bytes.position = 0;
while(bytes.bytesAvailable > 0) {
    fileStream.writeByte(bytes.readByte());
    trace("progress:", bytes.position / bytes.length * 100); // multiply by 100 for percentage
}

请注意,此方法需要一名工作人员,否则进度只会在保存完成后直观更新。

答案 2 :(得分:1)

Sunil是对的。写文件几乎不需要花点时间。它解码阻塞应用程序的字节数组。我实现了以下代码来测试它。

private function save(file:File):void
{
    var bytes:ByteArray = new ByteArray();
    //233348 - very fast (requires 6000 x 10000 bitmap pixels)
    //252790 - very fast (requires 6500 x 10000 bitmap pixels)
    //2488990 - need a whole magnitude more of data in order to show the progress messages
    for (var i:int = 0; i < 2488990; i++)
    {
        bytes.writeByte(1);
    }
    var fileStream:FileStream = new FileStream();
    fileStream.addEventListener(OutputProgressEvent.OUTPUT_PROGRESS, onProgress);
    fileStream.addEventListener(Event.CLOSE, onClose);
    try {
        fileStream.openAsync(file, FileMode.WRITE);
        fileStream.writeBytes(bytes);
    } catch (e:Error) {
        //Alert.show("Error trying to save the image: " + e.message);
    } finally {
        fileStream.close();
    }
}

您需要在解码任务上使用进度指示器而不是文件写入任务。工作者似乎是最好的解决方案,但这取决于您需要针对哪个版本的运行时。