Flex FileReference.save () может быть вызван только в обработчике пользовательских событий, как я могу обойти это?

Мне нужно вызвать FileReference.save () после завершения вызова веб-службы, но у этого метода есть ограничение: «В Flash Player вы можете успешно вызвать этот метод только в ответ на пользовательское событие (например, в обработчике событий для события щелчка мыши или нажатия клавиши). В противном случае вызов этого метода приведет к тому, что Flash Player выдаст исключение Error ". (из документации здесь)

Это ограничение немного расплывчато. Означает ли это, что я могу вызывать метод FileReference.save () только из функции обработчика событий, которая зарегистрирована как прослушиватель для определенных типов пользовательских событий? Если да, то какие именно пользовательские события действительны? (Возможно, есть событие, которое никогда не будет отправлено при взаимодействии пользователя с моим приложением, и я мог бы зарегистрировать функцию обработчика событий для этого типа события и сделать вызов save () из этой функции?)

Моя трудность заключается в том, что я не могу безопасно вызвать метод FileReference.save () до тех пор, пока моя веб-служба не вернется с данными, которые будут использоваться в качестве аргумента вызова метода FileReference.save (), поэтому событие, запускающее FileReference. Вызов save () на самом деле является ResultEvent, а не пользовательским событием, и я опасаюсь отправлять новый (поддельный) тип пользовательского события, чтобы иметь возможность запускать вызов FileReference.save (), если это определенно не пользовательское событие, которое никогда не будет отправлен в результате реального взаимодействия пользователя с моим приложением.

Вкратце, сейчас я делаю следующее: у меня есть функция, зарегистрированная как обработчик нажатия кнопки. В этой функции я вызываю свой веб-сервис для получения данных с сервера. У меня также есть функция обработчика результатов, которая вызывается после завершения вызова веб-службы, и именно здесь я хочу вызвать метод FileReference.save (), так как на данный момент я знаю, что данные готовы к сохранению в файл. Но вышеупомянутое ограничение мешает мне это сделать - я получаю сообщение об ошибке:

Error #2176: Certain actions, such as those that display a pop-up window, 
may only be invoked upon user interaction, for example by a mouse click 
or button press.

Я пробовал много вещей, чтобы обойти это, например, создать вторую функцию обработчика событий щелчка мышью с вызовом FileReference.save () внутри и вызвать ее после интервала тайм-аута (чтобы дать веб-сервису время для завершения), но я продолжаю возникает та же ошибка - возможно, этот подход не работает, поскольку вторая функция не зарегистрирована как прослушиватель событий для типа события, используемого в качестве его аргумента.

Я новичок в разработке Flex, поэтому, возможно, я просто неправильно об этом думаю. Если кто-то может предложить другой подход, я был бы очень признателен. Заранее благодарим за ваши комментарии или предложения.

--Джеймс


person James Adams    schedule 21.07.2010    source источник


Ответы (6)


Adobe делает это как своего рода меру безопасности, чтобы гарантировать, что именно пользователи возятся с файлами, а не с потенциально опасным кодом. Насколько я понимаю, они обеспечивают это, разрешая обработчикам событий (щелчков?), Которые происходят из компонентов пользовательского интерфейса, выполнять методы FileReference, поэтому создание ваших собственных событий программно не будет работать, хотя я не пытался это проверить. К сожалению, лучшее решение, которое я нашел, - это немного переработать пользовательский интерфейс, чтобы он соответствовал этому ограничению. В вашей конкретной ситуации вы можете сделать этот процесс двумя щелчками мыши с помощью кнопки, которая говорит что-то вроде «Подготовить загрузку», которая меняется на «Загрузить файл» после завершения работы веб-службы. Это далеко не идеально с точки зрения пользователя, но я не думаю, что что-то еще можно сделать, если только вы не сможете каким-либо образом завершить вызов веб-службы до отображения кнопки, запускающей вызов FileReference.save ().

person Wade Mueller    schedule 21.07.2010
comment
Это верно. Ожидается, что приложения Flash на основе браузера будут подчиняться обычным правилам песочницы браузера. Другой вариант - использовать Adobe AIR, который выходит за пределы изолированной программной среды браузера (но требует, чтобы пользователь установил приложение). - person James Ward; 21.07.2010

Поработав над этим, через пару часов я нашел обходной путь: вы можете использовать как события mouseDown, так и mouseUp вместо простого щелчка.

Например: s: Button mouseDown = "prepare_PDF ()" mouseUp = "save_PDF ()"

У меня отлично работает!

Удачного кодирования!

--Томас

person Thomas    schedule 19.12.2010
comment
Спасибо за это, Томас. Я не связывался с этим приложением какое-то время, поэтому у меня, возможно, никогда не будет возможности его протестировать, но оно выглядит как хорошее решение, и его следует знать и помнить. - person James Adams; 07.01.2011
comment
Если prepare_PDF асинхронный, похоже, что вы будете в состоянии гонки с save_PDF. Что делать в save_PDF, если prepare_PDF еще не завершен? - person paleozogt; 03.06.2011

В качестве обходного пути я использовал класс ExternalInterface. Я создал функцию javascript с этим кодом

function downloadFile (url) {
            window.open(url);
        }

Я звоню в AS3

var url = 'www.example.com/downloadfile.php?file_id=xxx';
ExternalInterface.call('downloadAttachmentFile', url);

Таким образом, я передаю обработку файлов на JS / HTML.

person havoc24k    schedule 12.11.2012
comment
Обратите внимание, отвечаете ли вы на активную ветку ... этой ветке 2 года, и на нее есть принятый ответ! - person durron597; 12.11.2012
comment
Да, но многие люди, подобные мне, попадают в старые темы из Google. Так почему бы не предложить альтернативу другому ищущему ответа, как я? - person havoc24k; 13.11.2012
comment
Согласованный. Я пришел сюда из поиска в Google и хочу получить свежие ответы, а не только те, которые понравились OP! - person Venryx; 18.10.2017

Это комментарий к ответу Томаса (у меня пока недостаточно XP для комментариев): обходные пути mousedown и mouseup работают хорошо. Просто обратите внимание, что если вы вносите какие-либо изменения в prepare_PDF(), которые требуют «отмены» в save_PDF(), то неплохо было бы вызвать этот код и для события mouseout, поскольку может быть случай, когда пользователь нажимает на кнопку, но затем отодвигает мышь от кнопки.

Это было особенно актуально для моего случая, когда мы увеличивали размер водяного знака на изображении, когда пользователь нажимает кнопку загрузки (которая запускает вызов .save()). Я уменьшаю размер водяного знака до нормального для событий mousedown и mouseout.

person Jaffer    schedule 09.02.2011
comment
Поскольку вы звоните в веб-службу, я не понимаю, как это работает. Вы запускаете вызов веб-службы из mouseDown и предполагаете, что он был завершен к моменту выполнения mouseUp. Что, если mouseUp произойдет до завершения вызова веб-службы? - person paleozogt; 03.06.2011
comment
@paleozogt вызов веб-службы запускается для mouseUp, а не для mouseDown. - person Jaffer; 10.06.2011
comment
В примере Томаса prepare_PDF (вызывается из mouseDown) - это вызов веб-службы, верно? Затем save_PDF (вызывается из mouseUp) вызывает FileReference.save. - person paleozogt; 10.06.2011
comment
Это все еще сбивает с толку, как это написано, если мы выполняем вызов AMF RemoteObject, как мы можем сделать этот вызов после, когда save () инициируется в mouseDown ()? - person Mifune; 11.04.2012

У меня была такая же проблема, я решил использовать методы flash.net. Вызов flash.net.navigateToURL(url); из сценария действий или navigateToURL(url); из mxml.

person Sam    schedule 14.06.2013

Что я делаю, чтобы решить эту проблему, так это показывать предупреждающее сообщение с анонимной функцией, поэтому мне не нужно создавать кнопку.

Alert.show("Do you wish to download the file?", "Confirm", Alert.OK | Alert.CANCEL, this, function (eventObj:CloseEvent):void {
                                                                                                    if (eventObj.detail == Alert.OK) {
                                                                                                        fileReference.save(zipOut.byteArray, dateFormater_titulo.format(new Date ()) + ".zip");
                                                                                                    }//if
                                                                                                 }/*function*/, null, Alert.OK);
person Carlos Castro    schedule 19.12.2016