Cordova:如何编写可以重复调用 Javascript 回调的本机插件?
Posted
技术标签:
【中文标题】Cordova:如何编写可以重复调用 Javascript 回调的本机插件?【英文标题】:Cordova: How to write native plugins that can repeatedly invoke a Javascript callback? 【发布时间】:2014-10-18 10:46:06 【问题描述】:在开发 Cordova 插件时,我找到的所有教程都是这样的:
文件:AwesomePlugin.js
var AwesomePlugin =
kungfuGripAction = function(target, successCallback, failureCallback)
return cordova.exec(
successCallback,
failureCallback,
'AwesomePluginClass',
'kungfuGripAction',
[target]
);
;
module.exports = AwesomePlugin;
文件:AwesomePluginClass.java
@Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException
if (ACTION_KUNGFU_GRIP.equals(action))
JSONObject target = args.getJSONObject(0);
if (gripTarget(target))
callbackContext.success("Target successfully gripped.");
return true;
else
callbackContext.error("Could not grip target.");
return false;
Log.d(LOG_TAG, "INVALID ACTION! " + action);
callbackContext.error("Invalid action: " + action);
return false;
文件:clientCode.js
AwesomePlugin.kungfuGripAction(cobraEnemy, function(ok) , function(err) );
在上面的代码中,回调只能被调用一次然后被释放。如果您尝试调用回调上下文对象的.success()
或.error()
方法,它将不起作用,您将收到一条日志消息:
Attempted to send a second callback for ID: AwesomePlugin2982699494<BR>W/CordovaPlugin(976) Result was: "Target successfully gripped."
似乎不可能编写带有可重复调用的回调的方法,因为 .success()
和 .error()
是唯一记录在案的从本机插件代码中调用回调的方法。虽然这主要是我们想要的,但有时我们希望插件重复执行回调。例如:
AwesomePlugin.kungfuGripAction(cobraEnemy, function(ok)
// After successful grip, punch repeatedly and update life meter.
AwesomePlugin.punchRepeatedly(cobraEnemy, function(hits)
updateLifeMeter(cobraEnemy, hits);
, function(err) );
, function(err) );
上面的AwesomePlugin.punchRepeatedly()
将重复执行(可能在单独的线程中)并在每次成功执行时调用function(hits)
。如果以事实上的方式实现(使用一次性回调),则必须在回调中使用循环(这很糟糕,因为它是非异步的)或尾部调用 AwesomePlugin.punchRepeatedly()
(容易出错)。
在本机代码中实现punchRepeatedly()
以便能够注册一次回调然后重复执行它的正确方法是什么?
【问题讨论】:
【参考方案1】:我认为,您可以使用 pluginResult
并将 keepCallback
属性设置为 true
。
PluginResult result = new PluginResult(PluginResult.Status.OK, "YOUR_MESSAGE");
// PluginResult result = new PluginResult(PluginResult.Status.ERROR, "YOUR_ERROR_MESSAGE");
result.setKeepCallback(true);
callbackContext.sendPluginResult(result);
您应该可以通过这种方式多次调用回调。
【讨论】:
谢谢,这行得通。PluginResult.setKeepCallback(true)
是关键。
@n.abing 这不是在每次发送新回调时通过 status.ok 多次触发成功回调吗?
@TimothyShamilov 不,它不会那样做。自从我在 Cordova 中编写任何内容以来已经有很长时间了,但 IIRC result.setKeepCallback(true)
仅确保当 result
被销毁时回调函数不会被销毁。如有疑问,请使用来源:)【参考方案2】:
在 jonas 的回答中,每次调用 sendPluginResult
时,都必须发送相同的值。所以我改变了 PluginResult 类来添加一个这样的方法:
public void setStrMessage(String strMessage)
this.strMessage = strMessage;
这样,我可以设置我要发送到javascript端的消息。
【讨论】:
您通常应该避免直接修改框架代码。当您升级 Cordova 框架时,您的更改将丢失。您也不需要更改插件结果中的消息,因为您在创建新实例然后将其发送到回调时已经设置了该消息。您唯一可能想要这样做的情况是,如果您在插件中重复使用PluginResult
的单个实例,这也是一个坏主意。
你是对的。但我的意思是通过设置 setKeepCallback (true) 来重用 Pluginresult 的单个实例,那么每次发送不同消息的更好方法是什么?在 swift 语言中我可以使用扩展
什么意思?您不必重复使用 PluginResult
的单个实例。您可以在每次需要将结果发回回调时实例化一个新的PluginResult
,并根据需要使用不同的消息。使用result.keepCallback(true)
只会告诉callbackContext.sendPluginResult()
不要将回调标记为“已使用”,以便您可以在再次发送结果时重用callbackContext
。
我明白你的意思了!你的意思是每个 Pluginresult 实例都应该 setKeepCallback(true) 吗?!非常感谢 ?
是的,在你创建PluginResult
的新实例后,你应该在sendPluginResult()
中使用它之前使用setKeepCallback(true),否则你会得到上面描述的错误。以上是关于Cordova:如何编写可以重复调用 Javascript 回调的本机插件?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 android 中远程更新我的 cordova/phonegap 移动应用程序?