Javascript 和 Phonegap 插件之间的异步通信
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19177991/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Asynchronous communication between Javascript and Phonegap Plugin
提问by Anas Azeem
So, everybody knows that we make a Class extending CordovaPlugin
and override the execute()
and then creates a bridge between the JS and native Java (for Android). Further we use PluginResult
to return the result back to the JS.
所以,每个人都知道我们创建一个类来扩展CordovaPlugin
和覆盖 execute()
,然后在 JS 和原生 Java(对于 Android)之间建立一座桥梁。此外,我们使用PluginResult
将结果返回给 JS。
So, all of this happens when there is a request fired from the JS to the Java Plugin. My question is, how to send a result back to JS(and therefore to HTML) asynchronously ?
因此,所有这些都发生在从 JS 向 Java 插件发出请求时。我的问题是,如何将结果异步发送回 JS(并因此发送回HTML)?
I don't know if the word asynchronousis right here. The thing is I want to send something back to the JS out of the blue (say, when wifi becomes enable/disable).
我不知道异步这个词是否在这里。问题是我想突然将一些东西发送回 JS(例如,当 wifi 启用/禁用时)。
I have already researched on this but haven't got anything which suits to my case.
我已经对此进行了研究,但没有任何适合我的情况。
The thing I've tried is -
我试过的事情是 -
- Created a
BroadcastReceiver
listening to theWiFi
events using theWifiManager
class. - Registered the receiver.
- And finally, popping a
Toast
whenWiFi
is enabled/disabled, and sending the result usingCallbackContext
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, "Wifi Connected"))
and for disconnected with a different message.
- 使用该类创建了
BroadcastReceiver
对WiFi
事件的监听WifiManager
。 - 注册接收器。
- 最后,弹出启用/禁用
Toast
whenWiFi
,并使用CallbackContext
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, "Wifi Connected"))
和 for disconnected发送结果,并使用 不同的消息。
MyPlugin.java
我的插件
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
...
public class MyPlugin extends CordovaPlugin {
private WifiReceiver wifiBroadcastReceiver = null;
private CallbackContext callbackContext = null;
...
public MyPlugin() {
wifiBroadcastReceiver = new WifiReceiver();
...
}
...
public boolean execute(String action, final JSONArray args,
final CallbackContext callbackId) throws JSONException {
IntentFilter wifiFilter = new IntentFilter(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
cordova.getActivity().registerReceiver(wifiBroadcastReceiver, wifiFilter);
this.callbackContext = callbackId;
...
}
public class WifiReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
if (intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, false)) {
Toast.makeText(cordova.getActivity(), "Wifi Connected", Toast.LENGTH_SHORT).show();
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, "Wifi Connected"));
} else {
Toast.makeText(cordova.getActivity(), "Wifi Disconnected", Toast.LENGTH_SHORT).show();
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, "Wifi Disconnected"));
}
}
}
}
The Toast
pops but the PluginResult
isn't sent to the JS.
在Toast
持久性有机污染物,但PluginResult
不发送给JS。
PS :Listening to WiFi events isn't my actual problem, I want to replicate the Android Bluetooth Chat
app in Phonegap. So, it has to be asynchronous in nature.
PS:收听WiFi事件不是我的实际问题,我想Android Bluetooth Chat
在Phonegap中复制该应用程序。因此,它本质上必须是异步的。
采纳答案by Simon MacDonald
You are almost there but you need to setKeepCallback to true on your PluginResult. If you don't the subsequent results from the Java side will not have a callback on the JavaScript side. The best example of this type of coding is the Network plugin in Cordova core. Here is a link to the source:
你快到了,但你需要在你的 PluginResult 上 setKeepCallback 为 true。如果不这样做,Java 端的后续结果将不会在 JavaScript 端有回调。此类编码的最佳示例是 Cordova 核心中的网络插件。这是源的链接:
So you should update your code to:
因此,您应该将代码更新为:
public boolean execute(String action, final JSONArray args,
final CallbackContext callbackId) throws JSONException {
IntentFilter wifiFilter = new IntentFilter(
WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
cordova.getActivity().registerReceiver(wifiBroadcastReceiver,
wifiFilter);
this.callbackContext = callbackId;
PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT);
result.setKeepCallback(true);
this.callbackContext.sendPluginResult(result);
return true;
}
public class WifiReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
PluginResult result;
if (intent.getBooleanExtra(
WifiManager.EXTRA_SUPPLICANT_CONNECTED, false)) {
Toast.makeText(cordova.getActivity(), "Wifi Connected",
Toast.LENGTH_SHORT).show();
result = new PluginResult(PluginResult.Status.OK,
"Wifi Connected");
} else {
Toast.makeText(cordova.getActivity(), "Wifi Disconnected",
Toast.LENGTH_SHORT).show();
result = new PluginResult(PluginResult.Status.ERROR,
"Wifi Disconnected");
}
result.setKeepCallback(false);
if (callbackContext != null) {
callbackContext.sendPluginResult(result);
callbackContext = null;
}
}
}
}
回答by Lucidity
Answer to 'second callback' warning...
回答“第二次回调”警告...
The Cordova source-code which triggers this warning can be found on line 57 here:
可以在此处的第 57 行找到触发此警告的 Cordova 源代码:
Thus - warning is caused because your CallbackContext object has 'finished=true'.
因此 - 警告是因为您的 CallbackContext 对象具有“finished=true”。
Most likely cause of this is you called: callbackContext.sendPluginResult(pluginResult);
最可能的原因是你打电话给: callbackContext.sendPluginResult(pluginResult);
Without first calling: pluginResult.setKeepCallback(true);
无需先调用: pluginResult.setKeepCallback(true);
If not... most likely you are unintentionally caching the CallbackContext object.
如果不是......很可能你无意中缓存了 CallbackContext 对象。
Your execute() function should assign CallbackContext each time it is called. See lines 125-127 in the code Simon linked to:
您的 execute() 函数应在每次调用时分配 CallbackContext。请参阅Simon 链接到的代码中的第 125-127 行:
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
if (action.equals("getConnectionInfo")) {`
this.connectionCallbackContext = callbackContext;
...
The proper sequence of events in full:
完整的正确事件顺序:
Make initial call to plugin.
Plugin saves reference to passed in CallbackContext object.
Keep CallbackContext object reference, while returning results with setKeepCallback(true).
When the sequence is finished, return with setKeepCallback(false) (the default)
对插件进行初始调用。
插件保存对传入 CallbackContext 对象的引用。
保留 CallbackContext 对象引用,同时使用 setKeepCallback(true) 返回结果。
序列完成后,返回 setKeepCallback(false)(默认)
Then later...
然后后来...
Make another call to plugin.
Plugin overwrites saved CallbackContext reference, replace with passed in object.
再次调用插件。
插件覆盖保存的 CallbackContext 引用,替换为传入的对象。
Then steps 3-4 same as above.
然后步骤 3-4 与上述相同。
Hope that helps :)
希望有帮助:)