Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Блоги Правила Справка Пользователи Календарь Поиск рулит! Сообщения за день Все разделы прочитаны
 

Вернуться   Форум Flasher.ru > Блоги > Котяра

Рейтинг: 5.00. Голосов: 3.

Глобальный ловец ошибок и неуловимый loaderInfo

Запись от Котяра размещена 09.10.2012 в 20:17
Обновил(-а) Котяра 11.10.2012 в 00:48

Не секрет, что с версии плеера 10.1 появилась возможность глобального отлова ошибок.

Но есть одно но!
Отлавливать ошибки может только loaderInfo документ класса, который, как оказалось, не равен stage.loaderInfo и не всегда root.loaderInfo.
Хотя stage.loaderInfo.parameters и т.п. читаются и совпадают.

Для 2-кадровой флэшки, где документ классом был класс прелоадера - пришлось передавать этот самый loaderInfo в класс главного приложения:
Код AS3:
private function startUp():void {
            var mainClass:Class = getDefinitionByName(_mainClassName) as Class;
            var main:DisplayObject = new mainClass();
            main["documentClassLoaderInfo"] = loaderInfo;
            stage.addChild(main);
        }
Cоответственно, нужно было завести в главном классе сеттер documentClassLoaderInfo.

Второй момент:
Отлов этого события всё-равно в дебаговом плеере не запрещен - появляется окошко с ошибкой и кнопками продолжить. Это бесит, а иногда просто не хватает реакции человека, чтобы нажать эту кнопку, ну и логика подразумевает некие тайминги.. Да и просто бесит)
Сидишь ютуб смотришь, а на тебя какая-то куча ошибок сыпется) Да - в дебаговом плеере смотреть ютуб нерепрезентативно. Но мне лень переключаться.
Ребята (разработчики вк, ютуба и прочих) - ловите ошибки у себя в логерах. Не давайте повод посмеяться другим разрабам: мол - вот блин - весь вк плеер сыпется еррорами, а мы чем хуже...

Решение (подсмотрено в org.as3commons.logging):

Код AS3:
 if ( _documentClassLoaderInfo.uncaughtErrorEvents){
                _documentClassLoaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR,
                        uncaughtErrorHandler);
            }
....
 
 private function uncaughtErrorHandler(event:UncaughtErrorEvent):void {
            event.preventDefault();
....
На этом всё.

UPD:
Выяснил когда происходит это неожиданное поведение.

root становится равным stage и не равным руту документ класса
если мы в Preloader будем делать
Код AS3:
stage.addChild(main);
а не

Код AS3:
addChild(main);
Т.е. для любых объектов добавленных напрямую на stage - root не равен документ классу, а равен stage.
На этом точно всё.
Всего комментариев 10

Комментарии

Старый 10.10.2012 01:08 gloomyBrain вне форума
gloomyBrain
 
Аватар для gloomyBrain
Коротко и по делу. Спасибо.
Старый 10.10.2012 01:09 Котяра вне форума
Котяра
 
Аватар для Котяра
На это "коротко" убил почти целый рабочий день)
Ну чтобы понять, что documentClassLoaderInfo != stage/root.loaderInfo
Обновил(-а) Котяра 11.10.2012 в 02:51
Старый 10.10.2012 06:25 artcraft вне форума
artcraft
 
Аватар для artcraft
Цитата:
documentClassLoader != stage/root.loaderInfo
ценно, спасибо что поделился
Старый 10.10.2012 10:43 dimarik вне форума
dimarik
 
Аватар для dimarik
Немного не понимаю почему у тебя root не указывает на DocumentClass. Вот же, все правильно сделал.
Код AS3:
/**
 * Constructor
 */
public function DocumentClass() {
    trace(this === root); // true;
    trace(this === stage); // Compile-time error: 1176: Comparison between a value with static type DocumentClass and a possibly unrelated type flash.display:Stage.
 
    trace(stage.loaderInfo === root.loaderInfo); // false
    trace(super.loaderInfo === root.loaderInfo); // true
 
    const s:Sprite = new Sprite();
    trace('before add child', s.loaderInfo); // null
    super.addChild(s);
    trace('after add child', s.loaderInfo, s.loaderInfo === this.loaderInfo); // [object LoaderInfo] true
    super.removeChild(s);
    trace('after remove child', s.loaderInfo); // null
}
this и stage — это разные штуки и ссылки loaderInfo ведут на разные LoaderInfo, ежу понятно.

Фактически существует один LoaderInfo на файл. И плюс один LoaderInfo на Stage. Stage LoaderInfo#parameters и LoaderInfo#parameters файла stage owner разделяют значения, они копируются. У подгружаемых SWF parameters свои.

В справке сказано, что uncaughtErrorEvents отлавливает ошибки "в коде SWF-файла данного объекта LoaderInfo." У stage нет кода SWF, у него только дети-SWF. Вот в дитях и ловите ошибки. По-моему все чётко.
Старый 10.10.2012 13:23 Котяра вне форума
Котяра
 
Аватар для Котяра
Дима, каюсь для однокадровой флэшки не проверял.
но в классе, который создаётся прелдоадером
Код AS3:
var main:DisplayObject = new mainClass();
в addedToStageHandler
имеем следующее:
Код AS3:
trace("stage.loaderInfo == _documentClassLoaderInfo :" , (stage.loaderInfo == _documentClassLoaderInfo));
trace("root.loaderInfo == stage.loaderInfo :" , (root.loaderInfo == stage.loaderInfo));
trace("root.loaderInfo == _documentClassLoaderInfo :" , (root.loaderInfo == _documentClassLoaderInfo));
результат:

Код AS3:
stage.loaderInfo == _documentClassLoaderInfo : false
root.loaderInfo == stage.loaderInfo : true
root.loaderInfo == _documentClassLoaderInfo : false
И ошибки отлавливаются только на _documentClassLoaderInfo
Т.е. факт что не всегда:
Цитата:
Фактически существует один LoaderInfo на файл.
Обновил(-а) Котяра 10.10.2012 в 17:50
Старый 10.10.2012 18:53 Котяра вне форума
Котяра
 
Аватар для Котяра
Ничего не понимаю.. Собрал в FD тестовую флэшку на основе темплейта с Preloader.
Код AS3:
package {
    import flash.display.DisplayObject;
	import flash.display.LoaderInfo;
    import flash.display.MovieClip;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.events.IOErrorEvent;
    import flash.events.ProgressEvent;
    import flash.utils.getDefinitionByName;
 
    public class Preloader extends MovieClip {
 
        public function Preloader() {
            if (stage) {
                stage.scaleMode = StageScaleMode.NO_SCALE;
                stage.align = StageAlign.TOP_LEFT;
            }
            addEventListener(Event.ENTER_FRAME, checkFrame);
            loaderInfo.addEventListener(ProgressEvent.PROGRESS, progress);
            loaderInfo.addEventListener(IOErrorEvent.IO_ERROR, ioError);
 
            // TODO show loader
        }
 
        private function ioError(e:IOErrorEvent):void {
            trace(e.text);
        }
 
        private function progress(e:ProgressEvent):void {
            // TODO update loader
        }
 
        private function checkFrame(e:Event):void {
            if (currentFrame == totalFrames) {
                stop();
                loadingFinished();
            }
        }
 
        private function loadingFinished():void {
            removeEventListener(Event.ENTER_FRAME, checkFrame);
            loaderInfo.removeEventListener(ProgressEvent.PROGRESS, progress);
            loaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, ioError);
 
            // TODO hide loader
 
            startup();
        }
 
        private function startup():void {
			var _documentClassLoaderInfo:LoaderInfo = this.loaderInfo;
            trace("---------------In preloader----------------");
            trace("stage.loaderInfo == _documentClassLoaderInfo :", (stage.loaderInfo == _documentClassLoaderInfo));
            trace("root.loaderInfo == stage.loaderInfo :", (root.loaderInfo == stage.loaderInfo));
            trace("root.loaderInfo == _documentClassLoaderInfo :", (root.loaderInfo == _documentClassLoaderInfo));
 
            var mainClass:Class = getDefinitionByName("Main") as Class;
            var main:DisplayObject = new mainClass();
            main["documentClassLoaderInfo"] = _documentClassLoaderInfo;
            addChild(main);
 
        }
 
    }
 
}
Код AS3:
package {
    import flash.display.LoaderInfo;
    import flash.display.Sprite;
    import flash.events.Event;
 
    [Frame(factoryClass="Preloader")]
 
    public class Main extends Sprite {
        private var _documentClassLoaderInfo:LoaderInfo;
 
        public function Main():void {
            if (stage)
                init();
            else
                addEventListener(Event.ADDED_TO_STAGE, init);
        }
 
        private function init(e:Event = null):void {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            trace("---------------In Main----------------");
            trace("stage.loaderInfo == _documentClassLoaderInfo :", (stage.loaderInfo == _documentClassLoaderInfo));
            trace("root.loaderInfo == stage.loaderInfo :", (root.loaderInfo == stage.loaderInfo));
            trace("root.loaderInfo == _documentClassLoaderInfo :", (root.loaderInfo == _documentClassLoaderInfo));
        }
 
        public function set documentClassLoaderInfo(value:LoaderInfo):void {
            _documentClassLoaderInfo = value;
        }
 
    }
 
}
Цитата:
---------------In preloader----------------
stage.loaderInfo == _documentClassLoaderInfo : false
root.loaderInfo == stage.loaderInfo : false
root.loaderInfo == _documentClassLoaderInfo : true
---------------In Main----------------
stage.loaderInfo == _documentClassLoaderInfo : false
root.loaderInfo == stage.loaderInfo : false
root.loaderInfo == _documentClassLoaderInfo : true
Рузультат соответствует теории димарика.. Что же тогда в моём проекте такого странного происходит, что результат другой?..
Буду копать.
Обновил(-а) Котяра 10.10.2012 в 19:06
Старый 10.10.2012 19:44 Котяра вне форума
Котяра
 
Аватар для Котяра
Я понял разницу.
Если главный класс размещать внутри прелоадера, то будет
ожидаемое поведение.
Код AS3:
 private function startup():void {
	    var _documentClassLoaderInfo:LoaderInfo = this.loaderInfo;
            var mainClass:Class = getDefinitionByName("Main") as Class;
            var main:DisplayObject = new mainClass();
            main["documentClassLoaderInfo"] = _documentClassLoaderInfo;
            addChild(main);
        }
Ежели мы чуть-чуть изменим код (как было в случае моего проекта)
Код AS3:
 private function startup():void {
	    var _documentClassLoaderInfo:LoaderInfo = this.loaderInfo;
            var mainClass:Class = getDefinitionByName("Main") as Class;
            var main:DisplayObject = new mainClass();
            main["documentClassLoaderInfo"] = _documentClassLoaderInfo;
            stage.addChild(main); // вот он  - камень преткновенья
        }
то в трэйсах получим картину
Цитата:
---------------In preloader----------------
stage.loaderInfo == _documentClassLoaderInfo : false
root.loaderInfo == stage.loaderInfo : false
root.loaderInfo == _documentClassLoaderInfo : true
---------------In Main----------------
stage.loaderInfo == _documentClassLoaderInfo : false
root.loaderInfo == stage.loaderInfo : true
root.loaderInfo == _documentClassLoaderInfo : false
Обновил(-а) Котяра 11.10.2012 в 00:50
Старый 11.10.2012 23:50 dimarik вне форума
dimarik
 
Аватар для dimarik
Судя по
Код:
---------------In Main----------------
stage.loaderInfo == _documentClassLoaderInfo : false
root.loaderInfo == stage.loaderInfo : true
root.loaderInfo == _documentClassLoaderInfo : false
Резюме: при добавлении чего-то на Stage, то Stage#loaderInfo будет равным последнему добавленному DocumentClass#loaderInfo?

Запутал ты меня, Костя. Я не зря приводил пример со спрайтом. Куда ты добавил сиротливый Main? Там у него и root, ведущий к файлу-документклассу или к Stage, если его добавили на него.

Разберем построчно.
Код:
stage.loaderInfo === _documentClassLoaderInfo : false
Это нормально. У Stage всегда есть свой собственный LoaderInfo;
Код:
root.loaderInfo === stage.loaderInfo : true
Потому что root у помещенного на Stage DisplayObject и есть stage ('after add child to stage' root == stage);

Цитата:
root.loaderInfo == _documentClassLoaderInfo : false
Читай
Код:
stage.loaderInfo == _documentClassLoaderInfo : false
Обновил(-а) dimarik 12.10.2012 в 00:08
Старый 12.10.2012 02:06 Котяра вне форума
Котяра
 
Аватар для Котяра
Цитата:
Потому что root у помещенного на Stage DisplayObject и есть stage
Я это уже понял. Это логично. Но я был уверен, что документкласс - всегда owner stage, и он будет всегда рутом, для объектов в списке отображения.


Но тут, вдруг, оказалось, что это не так.
И вообще я начал с отлова ошибок, а понял дзен.
Дима - спасибо. Ты своими комментариями меня направил)
Старый 12.10.2012 10:05 dimarik вне форума
dimarik
 
Аватар для dimarik
Еще немного дзена не повредит.
Цитата:
Но я был уверен, что документкласс - всегда owner stage
Только праймари документкласс может быть owner stage, покуда stage у него не отобрали. На твоей картинке изображен типичный праймари документкласс. Подгружаемые файлы не являются праймари документклассами. Помните эти страшные муки, когда в конструкторе загруженной swf обращаются к stage?
 

 


Часовой пояс GMT +4, время: 15:06.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.