Flex 3 Close UrlLoader throws exception
I am trying to simulate a 'HEAD' method using UrlLoader; essentially, I just want to check for the presence of a file without downloading the entire thing. I figured I would just use HttpStatusEvent, but the following code throws an exception (one that I can't wrap in a try/catch block) when you run in debug mode.
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" initialize="init()">
<mx:Script>
<![CDATA[
private static const BIG_FILE:String = "http://www.archive.org/download/gspmovvideotestIMG0021mov/IMG_0021.mov";
private var _loader:URLLoader;
private function init():void {
_loader = new URLLoader();
_loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, statusHandler);
_loader.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
_loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, errorHandler);
_loader.load(new URLRequest(BIG_FILE));
}
public function unload():void {
try {
开发者_Python百科 _loader.close();
_loader.removeEventListener(HTTPStatusEvent.HTTP_STATUS, statusHandler);
_loader.removeEventListener(IOErrorEvent.IO_ERROR, errorHandler);
_loader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, errorHandler);
}
catch(error:Error) {
status.text = error.message;
}
}
private function errorHandler(event:Event):void {
status.text = "error";
unload();
}
private function statusHandler(event:HTTPStatusEvent):void {
if(event.status.toString().match(/^2/)) {
status.text = "success";
unload();
}
else {
errorHandler(event);
}
}
]]>
</mx:Script>
<mx:Label id="status" />
I tried using ProgressEvents instead, but it seems that some 404 pages return content, so the status event will correctly identify if the page exists.
Anyone have any ideas?
It's a bug in the URLLoader class, I think.
If you read the error message (at least the one I got, you haven't pasted yorrs!) you will see it:
Error: Error #2029: This URLStream object does not have a stream opened at flash.net::URLStream/readBytes() at flash.net::URLLoader/onComplete()
This gives you some insight on what's happening. The URLLoader class internally uses a URLStream object, which provides low-level access to the downloaded data.
The error message indicates that an onComplete handler is being called on URLLoader. The file is big but it's probably cached so it loads rather fast. Now, if you add a listener for both progress and complete events, you'll see the order in which events are fired is this:
- progress
- status
- complete
The docs confirm this:
Note that the httpStatus event (if any) is sent before (and in addition to) any complete or error event.
Now, you can see the problem is that from the status handler you're calling close(). This closes the stream. But apparently (and this is the bug, I think), the onComplete handler in the URLLoader class does not check whether the stream is open or not. (From Actionscript there's no way to check this, so you'd have to wrap code in try/catch). You cannot read data from a closed stream, so this is why it blows.
I can see 2 ways to fix this:
1) Defer execution of the function that calls close() (your unload method), so close() is called after the URLLoader internal onComplete method is called.
That is, do this:
setTimeout(unload,1);
instead of this:
unload();
2) Use a URLStream instead of a URLLoader. The first option strikes me as a bit of a hackish workaround, so I'd go with this last one in your situation. Using a URLStream means more work on your side, generally, but in this case you're not actually interested in reading any data, so it doesn't make much difference. Plus, you'd only have to change two lines in your current code:
This one:
private var _loader:URLStream;
And this one:
_loader = new URLStream();
And you're all set.
I have run into a similary issue.
What I discovered to be the problem was this call:
_loader.close();
The error occurred when I tried to close a file that I had not even opened. So in "try" clause, do a check for if the file is open before you try to close it.
Mike
精彩评论