Flex 的 FileReference.save() 只能在用户事件处理程序中调用——我该如何解决这个问题?
Posted
技术标签:
【中文标题】Flex 的 FileReference.save() 只能在用户事件处理程序中调用——我该如何解决这个问题?【英文标题】:Flex's FileReference.save() can only be called in a user event handler -- how can I get around this? 【发布时间】:2011-03-19 03:03:07 【问题描述】:我需要在 Web 服务调用完成后调用 FileReference.save(),但此方法有一个限制:“在 Flash Player 中,您只能成功调用此方法以响应用户事件(例如,在鼠标单击或按键事件的事件处理程序)。否则,调用此方法会导致 Flash Player 引发错误异常。 (来自文档here)
这个限制有点模糊。这是否意味着我只能从注册为某些类型用户事件的侦听器的事件处理函数中调用 FileReference.save() 方法?如果是这样,那么究竟哪些用户事件是有效的? (也许有一个事件永远不会被用户与我的应用程序交互分派,我可以为该事件类型注册一个事件处理函数并在该函数中进行 save() 调用?)
我的困难是我不能安全地调用 FileReference.save() 方法,直到我的 Web 服务返回将用作 FileReference.save() 方法调用的参数的数据,所以触发的事件FileReference.save() 调用实际上是一个 ResultEvent 而不是用户事件,我对调度一个新的(假的)用户事件类型持怀疑态度,以便能够触发 FileReference.save() 调用,除非它绝对是一个由于用户与我的应用程序的实际交互,永远不会分派的用户事件。
简而言之,我现在正在做的是:我有一个注册为按钮单击处理程序的函数。在这个函数中,我调用 Web 服务从服务器获取数据。我还有一个结果处理函数,它在 Web 服务调用完成时被调用,我想在这里调用 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() 调用创建第二个鼠标单击事件处理函数,并在超时间隔后调用它(给 Web 服务时间来完成),但我一直遇到同样的错误——也许这种方法不起作用,因为第二个函数没有注册为用作其参数的事件类型的事件侦听器。
我是 Flex 开发的新手,所以也许我只是没有以正确的方式思考这个问题。如果有人可以提出另一种方法,我将不胜感激。提前感谢您的 cmets 或建议。
--詹姆斯
【问题讨论】:
【参考方案1】:Adobe 将此作为一种安全措施,以确保用户是那些弄乱文件而不是潜在有害代码的人。我的理解是,他们通过仅允许源自 UI 组件的(单击?)事件的处理程序执行 FileReference 方法来强制执行此操作,因此以编程方式生成您自己的事件将不起作用,尽管我没有尝试验证这一点。不幸的是,我发现的最佳解决方案是重新设计 UI 以符合此约束。在您的特定情况下,您可以使用类似“准备下载”的按钮将其设为两次单击过程,该按钮会在 Web 服务完成后更改为“下载文件”。从用户的角度来看,这不太理想,但我认为没有什么可以做的,除非您可以在显示触发 FileReference.save() 调用的按钮之前以某种方式完成 Web 服务调用。
【讨论】:
这是准确的。基于浏览器的 Flash 应用程序应遵守正常的浏览器沙盒规则。另一种选择是使用 Adobe AIR,它在浏览器沙箱之外(但需要用户安装应用程序)。【参考方案2】:为此苦苦挣扎了几个小时后,我找到了一种解决方法:您可以同时使用 mouseDown 和 mouseUp 事件,而不仅仅是单击。
例如: s:按钮 mouseDown="prepare_PDF()" mouseUp="save_PDF()"
对我来说很好用!
编码愉快!
--托马斯
【讨论】:
谢谢你,托马斯。我已经有一段时间没有弄乱这个应用程序了,所以我可能永远没有机会测试它,但它看起来是一个很好的解决方案,值得了解和记住。 如果 prepare_PDF 是异步的,那么您似乎将处于使用 save_PDF 的竞争状态。如果 prepare_PDF 还没有完成,你在 save_PDF 中做什么?【参考方案3】:作为一种解决方法,我使用了 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。
【讨论】:
请注意您是否正在回复一个活跃的线程......这个线程是2岁并且有一个接受的答案! 是的,但是很多像我这样的人最终都在谷歌的“旧”线程上。那么为什么不为像我这样的另一个寻求答案的人提供替代方案呢? 同意。我通过 Google 搜索来到这里,想要最新的答案,而不仅仅是 OP 喜欢的答案!【参考方案4】:这是对 Thomas 回答的评论(我还没有足够的 XP 来评论):mousedown
和 mouseup
解决方法效果很好。请注意,如果您在 prepare_PDF()
中进行任何需要在 save_PDF()
中“撤消”的更改,那么在 mouseout
事件中调用该代码也是一个好主意,因为可能存在用户mousedown 在按钮上,但随后将鼠标从按钮上移开。
这与我的案例特别相关,在该案例中,当用户单击下载按钮(触发.save()
调用)时,我们增加了图像上水印的大小。我在mousedown
和mouseout
事件上将水印的大小减小到正常值。
【讨论】:
由于您正在进行网络服务调用,我不明白这是如何工作的。您从 mouseDown 触发 Web 服务调用,并假设它在 mouseUp 发生时已完成。如果 mouseUp 在 web 服务调用完成之前发生怎么办? @paleozogt web 服务调用在 mouseUp 上触发,而不是 mouseDown。 在 Thomas 的示例中,prepare_PDF
(从 mouseDown
调用)是 Web 服务调用,对吗?然后save_PDF
(从mouseUp
调用)调用FileReference.save。
这里的写法还是让人困惑,如果我们在做一个 AMF RemoteObject 调用,我们怎么能调用 在 save() 在 mouseDown( )?【参考方案5】:
我有同样的问题,我选择使用 flash.net 方法。从 actionscript 调用 flash.net.navigateToURL(url);
或从 mxml 调用 navigateToURL(url);
。
【讨论】:
【参考方案6】:我解决这个问题的方法是使用匿名函数显示警报消息,这样我就不必创建按钮。
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);
【讨论】:
以上是关于Flex 的 FileReference.save() 只能在用户事件处理程序中调用——我该如何解决这个问题?的主要内容,如果未能解决你的问题,请参考以下文章