【问题标题】:Why does URLStream complete event get dispatched when the file is not finished loading?为什么在文件未完成加载时会调度 URLStream 完成事件?
【发布时间】:2013-01-24 03:08:04
【问题描述】:

我正在编写一个 AIR kiosk 应用程序,它每晚都会连接到 WordPress 服务器,获取包含所有内容路径的 JSON 文件,然后下载该内容并将其保存到 kiosk 硬盘驱动器。

有数百个文件(jpg、png、f4v、xml),其中大多数可以毫无问题地下载/保存。但是,有两个 f4v 文件永远不会完全下载。 complete 事件确实被调度了,但是如果我比较 bytesTotal (来自 progress 事件)与 bytesAvailable (来自 complete 事件)它们不匹配; bytesTotal 更大。 bytesTotal(来自进度事件)与服务器上的字节匹配。

进度事件中的 bytesLoaded 永远不会增加到与 bytesTotal 匹配的程度,因此我也不能依赖进度事件。这似乎每次都发生在相同的两个视频上。视频不是很大,一个是13MB,一个是46MB。我有较大的视频可以毫无问题地下载。

编辑:重启我的电脑后,这两个视频现在已经完成下载,但我在 300kb png 文件时遇到了同样的问题。

如果我将 url 粘贴到 Firefox 中,它会正确下载。我还编写了一个简单的 c# 应用程序来下载文件,它能够毫无问题地下载它们,所以它似乎是 Flash/AIR 的问题。

编辑:这是一个更简单的代码版本,来自一个测试项目,它是唯一的代码(网址在我们的本地网络上,因此您无法自己下载文件):

package  {

    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.ProgressEvent;
    import flash.net.URLRequest;
    import flash.net.URLStream;

    [SWF(backgroundColor="#000000", frameRate="24", width="640", height="480")]

    public class Test extends Sprite {

        private var fileSize:Number;
        private var stream : URLStream;
        private var url:String = "http://192.168.150.219/wordpress2/wp-content/uploads/2012/12/John-Butler-clip1.f4v";

        public function Test() {
            if (stage)
                init();
            else
                this.addEventListener(Event.ADDED_TO_STAGE, init);
        }

        private function init(e:Event=null):void {
            this.removeEventListener(Event.ADDED_TO_STAGE, init);
            stream = new URLStream();
            stream.addEventListener(ProgressEvent.PROGRESS, onLoadProgress);
            stream.addEventListener(Event.COMPLETE, onLoadComplete);
            stream.load(new URLRequest(url));
        }

        private function onLoadProgress(event:ProgressEvent):void {
            fileSize = event.bytesTotal;
            var percent:Number = event.bytesLoaded / event.bytesTotal * 100;
            trace(percent + "%"); // this never gets to 100%
        }

        private function onLoadComplete(event:Event):void {
            trace("loaded", stream.bytesAvailable, "of", fileSize); 
            // outputs "loaded 13182905 of 13184365"
            // so why is it "complete" when it isn't fully downloaded?
        }
    }
}

【问题讨论】:

  • 嗨!代码太长,几分钟后无法理解.. 下次请只包括问题所在的部分.. a) 在 loadNext() 中您调度事件,但您在 mEventManager 上收听它,而不是这个。如果没问题,您可以编辑 onStreamProgress() 以检查是否 (e.loadedbytes == e.bytestotal),并手动调用完整函数。希望它有所帮助,我真的刚刚接触到代码。
  • 好吧,我不完全确定问题出在哪里:) 我正在调度的完整事件不是我在 init() 方法中收听的事件,而是添加到网址流。当队列中的所有项目都完成下载/保存后,我会调度另一个类正在侦听的完整事件。

标签: actionscript-3 flash air


【解决方案1】:

不要与bytesAvailable 比较,而是使用length。 BytesAvailable 实际上是ByteArray.length - ByteArray.position。因此,如果 ByteArray 中的位置已远离索引 0,则 bytesAvailable 值将减小。长度始终是数组中的总字节数。

尝试使用长度进行比较,看看这是否有什么不同。我没有时间筛选您的代码以查看您是否在任何时候更改位置(有意或无意;您可以通过多种方式进行更改),所以这是我现在能提供的最好的。

【讨论】:

  • 我不会在任何时候更改字节数组的位置。当 URLStream 调度完成事件时,我将整个事件读入一个新的字节数组,然后将该字节数组保存到磁盘。此外,URLStream 和 ProgressEvent 都没有长度属性,bytesLoaded、bytesTotal 和 bytesAvailable 都是我必须使用的。
  • 哦,你是对的。我习惯于在 COMPLETE 事件触发后立即将数据写入 ByteArray 并检查 ByteArray 上的长度属性。对于那个很抱歉。我唯一能想到的另一件事是在某个时候快速写入数据,但我检查过,在 COMPLETE 事件触发之前你不要这样做。我不知道为什么会发生这种情况。
【解决方案2】:

如果其他人有和我一样的问题。事实证明,AIR 中也存在缓存问题,因此添加到请求中的时间戳可以解决此问题:http://www.newtonflash.com/blog/as3/prevent-xml-caching-problem/#comment-43

{
var xmlPath:String="replaceYourXMLPathHere.xml"
var urlReq:URLRequest = new URLRequest(xmlPath+"?time=" + new Date().getTime());
}

【讨论】:

  • 这可能已经成功了,不幸的是我现在不能测试它,应用程序已经发布了。我最终使用 NativeProcess 和一个 c# 控制台应用程序进行下载。无论如何,我不是 100% 的时间戳会起作用,因为我遇到了以前未下载的文件的问题。
【解决方案3】:

你的答案就在你的问题中。

普通 URLs(文件)- 对于此服务器,这是一个数据块。一旦服务器交付“数据块”,交付过程就被视为“完成”。在这种情况下,如果文件为 100kb,一旦收到 100kb - Flash 将其视为“COMPLETE”。

URLStream - 对于服务器来说,这是 [TWO] 块数据(查看方式非常简单)。服务器将首先将 CONNECTION 提供给流...然后提供 STREAM DATA。正如其描述的那样,这是在 Flash 中处理的。

Flash 会将 CONNECTION 的加载视为“COMPLETE”,并NEVER检查STREAM数据已加载 - 这取决于您的服务器。在任何流中,您实际上都应该检查 [load progress] 事件并在数据进入时读取每个字节......然后根据需要进行构造。

【讨论】:

  • 在我编辑之前发布的第一个版本的课程中,我确实在进度事件期间将流写入磁盘,但它仍然没有完成。如果我忽略了完整的事件并且只通过 bytesLoaded/bytesTotal,它永远不会完成,因为 bytesLoaded 总是小于 bytesTotal,一旦完成大约 99.98%,我就会停止获取进度事件。我写了一个快速的 c# 应用程序,它可以下载文件并且它工作正常,进度事件达到 100%。这让我相信问题出在 Flash/AIR 上。
  • 还想补充一下,根据AS3文档,URLStream不应该在数据下载成功之前调度完成事件。这就是它与我正在下载的所有数百个其他文件的工作方式,它只是 AIR 似乎无法完全下载的两个特定视频。
  • 对不起,当我说流连接将被视为“完成”时,我有点错过了领导。由于流的性质,Flash 永远不会触发流的完成事件 - 也就是在服务器为终止字节提供服务之前,它永远不会完成。在代码中,您应该监听 url 进度事件并发送指针以记录文件传输何时开始/结束。从技术上讲,如果服务器可以处理 URLStream,您可以永远保持打开状态 - 因此 Flash 总是认为 URLStream 仍在加载而不是“完成”
  • Flash 确实会触发 URLStream 的完整事件。如果您阅读 API 文档,您会看到当数据传输成功完成时,会触发 complete 事件。对于我正在下载的大多数文件,完整事件按预期工作。正如我之前所说,我不能使用 ProgressEvent,因为对于下载失败的文件,bytesLoaded 总是小于 bytesTotal。它通常达到大约 99.98%,然后不再触发 ProgressEvents。
  • @Dave Wolfe 看来我错过了你的要求。我的印象是您正在流式传输类似于需要打开的实时套接字连接的内容。我是否理解您仅向客户端计算机提供文件?同样在进度事件中,您不关心总字节数,只关心加载的字节数。由您来构造/反序列化加载的字节。
猜你喜欢
  • 2010-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多