I get a vague "Socket timeout." error on occasion when I am loading my site. I make various HTTP requests for PHP data and also am using a Loader() class instance. Can anyone shed some light on where this error might be coming from?
I wish there was more of an indication of where the error stemmed from...
Here is my code that I am using.
There are multiple problems going on, but the most important is that catch{} catches an error on first load. I have a fade in function that only works if the loader is fully loaded and I know that all of my URL links work, so it can't be that.
public function loadImage(url:String):void
{
this._imageURL = url;
this.alpha = 1.0; //need this because we might have just faded the image out
_ldr.alpha = 0.0;
_prog.alpha = 1.0;
_sqr.alpha = 0.0;
try
{
_ldr.close();
_ldr.unload();
}
catch(e:Error)
{
trace("error in bmdisplay: " + e.message);
}
if(!_imageURL)
{
return;
}
_loaded = false;
_ldr.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onProgress);
_ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
_ldr.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onError);
_ldr.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onError);
_ldr.load(new URLRequest(_imageURL));
}
Could you provide more precise information on what you're actually loading and how?
You should be able to get the exact request throwing the error by listening for the securityError and ioError events on the contentLoaderInfo of the Loader object.
Something like this:
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, errorListener);
loader.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, errorListener);
var request:URLRequest = new URLRequest(url);
loader.load(request);
...
private function errorListener(event:Event):void {
var url_causing_the_error:String = LoaderInfo(event.target).loaderURL;
...
}
Related
Greeting,
I'm currently facing a problem that my coroutine can't start. This is the first time I facing this issues and I can't find a proper solution online. Much appreciated if anyone can point me to the right direction to solve this issue.
Here are the code.
path_reference.GetDownloadUrlAsync().ContinueWith((Task<Uri> task) => {
if (!task.IsFaulted && !task.IsCanceled)
{
Debug.Log("Download URL: " + task.Result);
StartCoroutine(DownloadStuff(task.Result));
}
else
{
Debug.Log(task.Exception.ToString());
}
});
}
IEnumerator DownloadStuff(Uri uri)
{
Debug.Log("Start Download");
using (var www = UnityWebRequestTexture.GetTexture(uri))
{
yield return www.SendWebRequest();
if (www.isNetworkError || www.isHttpError)
{
Debug.Log(www.error);
}
else
{
var texture = DownloadHandlerTexture.GetContent(www);
//Texture2D texture = new Texture2D(1, 1);
//if you need sprite for SpriteRenderer or Image
Sprite sprite = Sprite.Create(texture, new Rect(0.0f, 0.0f, texture.width,
texture.height), new Vector2(0.5f, 0.5f), 100.0f);
Debug.Log("Finished downloading!");
}
Debug.Log(www.downloadProgress);
}
}'
The task returned by Firebase probably finishes execution on a thread other than the main thread, and Unity coroutines can only run on the main thread.
Unity's support of multithreading and async is pretty spotty, including "eating" some errors if the continuations of those errors would execute on another thread other than the main thread.
To fix this, you need to change the function that starts your coroutine:
try {
// Important: ConfigureAwait(true) ensures the code after this will run in the
// same thread as the code before (which is the main thread!)
var url = await path_reference.GetDownloadUrlAsync().ConfigureAwait(true);
StartCoroutine(DownloadStuff(url));
} catch (Exception ex) {
// Tip: when logging errors, use LogException and pass the whole exception,
// that way you will get pretty links to the error line in the whole stack trace.
Debug.LogException(ex);
}
As an aside, I usually have a few extension methods on all my projects to deal with that while staying in async-world instead of coroutine-world (because at least with async I can catch errors and not just "halt and catch fire" like Unity's coroutines)
The main ones are:
public static Task ToTask(this YieldInstruction self, MonoBehaviour owner) {
var source = new TaskCompletionSource<object>();
IEnumerable Routine() {
yield return self;
source.SetResult(null);
}
return source.Task;
}
private static Task SendAsync(this UnityWebRequest self, MonoBehaviour owner) {
var source = new TaskCompletionSource<object>();
await self.SendWebRequest().ToTask(owner);
if (
self.isHttpError
|| self.isNetworkError
) {
source.SetException(new Exception(request.error));
yield break;
}
source.SetResult(null);
}
Which you can use like this, inside a MonoBehaviour:
await new WaitForSeconds(0.2f).ToTask(this);
UnityWebRequest request = /* etc */;
await request.SendAsync(this);
var texture = DownloadHandlerTexture.GetContent(request);
Note that these methods do not require ConfigureAwait, since their SetResult/SetException invocations are ran from Unity-provided coroutine continuations.
Core of my code is following:
var img:Image = new Image;
img.source = 'http://..........';
img.autoLoad = true;
img.cachePolicy = 'on';
img.addEventListener(Event.COMPLETE, function(event:Event):void {
trace('Loaded!', img.source);
});
img.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function(event:Event):void {
trace('Error!', img.source);
});
img.addEventListener(IOErrorEvent.IO_ERROR, function(event:Event):void {
trace('Error!', img.source);
});
I found that, the complete event does not occur for some images.
How can I catch complete event without signal leaks?
When you want to load an image (or even another swf) the class to use is Loader. A quick example:
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, handlerFunction);
loader.load(new URLRequest("http://somewhere/image.png"));
The only kind of tricky thing is that the events related to the loading are dispatched by the loader.contentLoaderInfo object, not the loader object.
And the always handy documentation:
Loader Class
I've been researching for days on the issude but till now I still haven found a solution yet.
I have 0 knowledge on ASP. And I just want to able to pass and get var/text from ASP.
Anyone kind enuff to guide me how I can furthur from here?
private function loadASP():void {
var aspSend:URLRequest=new URLRequest("testASP.asp");
var aspLoader:URLLoader = new URLLoader();
aspLoader.load(aspSend);
trace("did send");
//aspLoader.addEventListener(Event.COMPLETE, processASP);
}
private function processASP(e:Event):void {
}
Why have you commented the call to addEventListener method? Uncomment it (and move it up two lines so that it comes before the load call). If the url is correct, the processASP method will be called when the response arrives (in a real life application, make sure you listen for ioError and securityError on the URLLoader - check the link for examples on doing this). You can read the response as e.target.data in the processASP method.
private function processASP(e:Event):void
{
var loader:URLLoader = URLLoader(e.target);
trace("Response is " + loader.data);
}
URLLoader can also be used to send data to the asp page (server).
var ldr:URLLoader = new URLLoader();
var data:URLVariables = new URLVariables();
data.something = "someData";
data.somethingElse = "moreData";
var request:URLRequest = new URLRequest("url.asp");
request.data = data;
request.method = URLRequestMethod.POST;//or GET
ldr.addEventListener(Event.COMPLETE, onLoad);
//listen for other events
ldr.load(request);
Is it possible in an air application to start a download, pause it and after that resume it?
I want to download very big files (1-3Gb) and I need to be sure if the connection is interrupted, then the next time the user tries to download the file it's start from the last position.
Any ideas and source code samples would be appreciated.
Yes, you would want to use the URLStream class (URLLoader doesn't support partial downloads) and the HTTP Range header. Note that there are some onerous security restrictions on the Range header, but it should be fine in an AIR application. Here's some untested code that should give you the general idea.
private var _us:URLStream;
private var _buf:ByteArray;
private var _offs:uint;
private var _paused:Boolean;
private var _intervalId:uint;
...
private function init():void {
_buf = new ByteArray();
_offs = 0;
var ur:URLRequest = new URLRequest( ... uri ... );
_us = new URLStream();
_paused = false;
_intervalId = setInterval(500, partialLoad);
}
...
private function partialLoad():void {
var len:uint = _us.bytesAvailable;
_us.readBytes(_buf, _offs, len);
_offs += len;
if (_paused) {
_us.close();
clearInterval(_intervalId);
}
}
...
private function pause():void {
_paused = true;
}
...
private function resume():void {
var ur:URLRequest = new URLRequest(... uri ...);
ur.requestHeaders = [new URLRequestHeader("Range", "bytes=" + _offs + "-")];
_us.load(ur);
_paused = false;
_intervalId = setInterval(500, partialLoad);
}
if you are targeting mobile devices, maybe you should take a look at this native extension: http://myappsnippet.com/download-manager-air-native-extension/ it supports simultaneous resumable downloads with multi-section chunks to download files as fast as possible.
I am trying to use the following code to load styles from an external SWF, but I keep getting an ActionScript error when the URL is invalid:
Error: Unable to load style(Error #2036: Load Never Completed. URL: http://localhost/css/styles.swf): ../css/styles.swf.
at <anonymous>()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\styles\StyleManagerImpl.as:858]
private function loadStyles(): void
{
try
{
var styleEvent:IEventDispatcher =
StyleManager.loadStyleDeclarations("../styles.swf");
styleEvent.addEventListener(StyleEvent.COMPLETE,
loadStyle_completeHandler);
styleEvent.addEventListener(StyleEvent.ERROR,
loadStyle_errorHandler);
}
catch (error:Error)
{
useDefault();
}
}
private function loadStyle_completeHandler(event:StyleEvent): void
{
IEventDispatcher(event.currentTarget).removeEventListener(
event.type, loadStyle_completeHandler);
goToNextStep();
}
private function loadStyle_errorHandler(event:StyleEvent): void
{
IEventDispatcher(event.currentTarget).removeEventListener(
event.type, loadStyle_errorHandler);
useDefault();
}
I basically want to go ahead an use the default styles w/o the user seeing the error if this file can't be loaded - but I can't seem to find any way to do this.
Interesting problem. Try removing the removeEventListener call, or commenting it out; in my brief tests it appeared the event handler was being called twice (I'm not immediately sure why, although I suspect it has to do with style inheritance), and commenting that line did the trick.
If you have the same result, you might try just checking for the listener (using hasEventListener) first, before attaching it in your loadStyles() function, instead. Hope it helps!
** Not an answer, but an update:
FYI, this is the ActionScript code in the Source of mx.styles.StyleManagerImpl that is run when you call StyleManager.loadStyleDeclarations(). I ran the debugger and added a breakpoint at the Line 858("throw new Error(errorText);"), and the breakpoint was caught. I'm thinking it shouldn't be caught there, but the previous IF ("if (styleEventDispatcher.willTrigger(StyleEvent.ERROR))") should be run instead.
public function loadStyleDeclarations2(
url:String, update:Boolean = true,
applicationDomain:ApplicationDomain = null,
securityDomain:SecurityDomain = null):
IEventDispatcher
{
var module:IModuleInfo = ModuleManager.getModule(url);
var readyHandler:Function = function(moduleEvent:ModuleEvent):void
{
var styleModule:IStyleModule =
IStyleModule(moduleEvent.module.factory.create());
styleModules[moduleEvent.module.url].styleModule = styleModule;
if (update)
styleDeclarationsChanged();
};
module.addEventListener(ModuleEvent.READY, readyHandler,
false, 0, true);
var styleEventDispatcher:StyleEventDispatcher =
new StyleEventDispatcher(module);
var errorHandler:Function = function(moduleEvent:ModuleEvent):void
{
var errorText:String = resourceManager.getString(
"styles", "unableToLoad", [ moduleEvent.errorText, url ]);
if (styleEventDispatcher.willTrigger(StyleEvent.ERROR))
{
var styleEvent:StyleEvent = new StyleEvent(
StyleEvent.ERROR, moduleEvent.bubbles, moduleEvent.cancelable);
styleEvent.bytesLoaded = 0;
styleEvent.bytesTotal = 0;
styleEvent.errorText = errorText;
styleEventDispatcher.dispatchEvent(styleEvent);
}
else
{
throw new Error(errorText);
}
};
module.addEventListener(ModuleEvent.ERROR, errorHandler,
false, 0, true);
styleModules[url] =
new StyleModuleInfo(module, readyHandler, errorHandler);
// This Timer gives the loadStyleDeclarations() caller a chance
// to add event listeners to the return value, before the module
// is loaded.
var timer:Timer = new Timer(0);
var timerHandler:Function = function(event:TimerEvent):void
{
timer.removeEventListener(TimerEvent.TIMER, timerHandler);
timer.stop();
module.load(applicationDomain, securityDomain);
};
timer.addEventListener(TimerEvent.TIMER, timerHandler, false, 0, true);
timer.start();
return styleEventDispatcher;
}
I debugged the source, and found that the ERROR Event is being triggered twice. So, I simply set a flag the first time the ERROR event handler is triggered, and check that flag for a value of true before continuing:
private var isErrorTriggered:Boolean; // Default is false
private function loadStyle_completeHandler(event:StyleEvent):void
{
IEventDispatcher(event.currentTarget).removeEventListener(
event.type, loadStyle_completeHandler);
goToNextStep();
}
private function loadStyle_errorHandler(event:StyleEvent):void
{
if (isErrorTriggered)
return;
isErrorTriggered = true;
useDefault();
}