我正在尝试为Phonegap(Android)制作一个插件,允许我的javascript向/从服务发送和接收消息。 我确切的问题是,因为消息返回异步,我无法将PluginResult发送到插件的execute函数。
这是插件代码:
public class ServiceClient_plugin extends Plugin {
Messenger messenger_service=null;
boolean connected_to_service=false;
final Messenger messenger_receive = new Messenger(new IncomingHandler());
@Override
public PluginResult execute(String action, JSONArray data, String callbackId) {
PluginResult result = null;
try {
if (action.toUpperCase().equals("CONNECT")) {
result = ConnectService();
} else if (action.toUpperCase().equals("DISCONNECT")) {
result = DisconnectService();
} else if (action.toUpperCase().equals("IS_CONNECTED")) {
result = new PluginResult(Status.OK,connected_to_service);
} else if (action.toUpperCase().equals("COMMAND")) {
sendMSG (data.getString(0));
result = new PluginResult(Status.OK);
} else {
result = new PluginResult(Status.INVALID_ACTION);
}
} catch(JSONException e) {
result= new PluginResult(PluginResult.Status.JSON_EXCEPTION);
}
return result;
}
private PluginResult ConnectService() {
doBindService();
return new PluginResult(Status.OK);
}
private PluginResult DisconnectService() {
doUnbindService();
return new PluginResult(Status.OK);
}
class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MoMe_Service.MSG_COMMAND:
Log.i("CLIENT","Received from service: " + msg.getData().getString("MSG"));
break;
default:
super.handleMessage(msg);
}
}
}
private ServiceConnection service_connection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
messenger_service = new Messenger(service);
connected_to_service=true;
try {
Message msg = Message.obtain(null, My_Service.MSG_REGISTERED);
msg.replyTo = messenger_receive;
messenger_service.send(msg);
} catch (RemoteException e) {
// In this case the service has crashed before we could even
// do anything with it; we can count on soon being
// disconnected (and then reconnected if it can be restarted)
// so there is no need to do anything here.
}
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
messenger_service = null;
connected_to_service=false;
}
};
private void doBindService() {
// Establish a connection with the service. We use an explicit
// class name because there is no reason to be able to let other
// applications replace our component.
this.ctx.bindService(new Intent(this.ctx, My_Service.class), service_connection, Context.BIND_AUTO_CREATE);
}
private void doUnbindService() {
if (connected_to_service) {
if (messenger_service != null) {
try {
Message msg = Message.obtain(null, My_Service.MSG_UNREGISTERED);
msg.replyTo = messenger_receive;
messenger_service.send(msg);
} catch (RemoteException e) {
// There is nothing special we need to do if the service
// has crashed.
}
}
// Detach our existing connection.
this.ctx.unbindService(service_connection);
connected_to_service = false;
}
}
private void sendMSG (String message) {
try {
Message msg=Message.obtain(null, My_Service.MSG_COMMAND);
Bundle msg_bundle=new Bundle();
msg_bundle.putString("MSG", message);
msg.setData(msg_bundle);
messenger_service.send(msg);
} catch (RemoteException e) {
doUnbindService();
}
}
}
从这个插件真正的麻烦来自这部分代码,它处理返回消息和插件返回(转到javascript):
@Override
public PluginResult execute(String action, JSONArray data, String callbackId) {
PluginResult result = null;
try {
result = new PluginResult(Status.ok);
}
} catch(JSONException e) {
result= new PluginResult(PluginResult.Status.JSON_EXCEPTION);
}
return result;
}
class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MoMe_Service.MSG_COMMAND:
msg.getData().getString("MSG")); // THIS IS THE DATA I NEED RETURNED
break;
default:
super.handleMessage(msg);
}
}
}
我能想到的唯一解决方案是将响应存储在数据库或变量中,并让javascript执行setInterval以继续检查更改。但是我不太喜欢这个解决方案。我想使用某种回调函数让javascript知道消息已经返回,但我不知道如何。我非常感谢任何帮助和想法。
谢谢你, 维拉德
答案 0 :(得分:6)
这可能是一个迟到的答案,但我在5个月前开始使用Cordova插件,我刚看到你的问题。由于您没有选择正确的答案,我想回答您的问题。
假设你有异步流程,并且你有一个监听器和方法,成功和失败,我们称之为onSuccess()
和onFail()
。只要您使用pluginResult.setKeepCallback(true)
发送true,该过程将保持未完成状态,因此您可以在完成后台处理后稍后发送插件结果数据。这是一个例子来看看。
@Override
public boolean execute(String action, JSONArray data, String callbackId) throws JSONException {
if (action.equals("start")) {
start();
} else {
PluginResult pluginResult = new PluginResult(PluginResult.Status.INVALID_ACTION);
callbackContext.sendPluginResult(pluginResult);
return false;
}
}
private boolean start() throws JSONException {
MyClass.startProcess(new MyInterface() {
@Override
public void onSuccess(String data) {
PluginResult result = new PluginResult(PluginResult.Status.OK, data);
result.setKeepCallback(false);
callbackContext.sendPluginResult(result);
}
@Override
public void onFail() {
PluginResult result = new PluginResult(PluginResult.Status.ERROR);
result.setKeepCallback(false);
callbackContext.sendPluginResult(result);
}
});
PluginResult.Status status = PluginResult.Status.NO_RESULT;
PluginResult pluginResult = new PluginResult(status);
pluginResult.setKeepCallback(true);
callbackContext.sendPluginResult(pluginResult);
return true;
}
答案 1 :(得分:4)
我的问题的答案实际上是在PluginResult对象和成功方法中。 我找到了一个插件,为了工作必须面对同样的问题,从这个代码我能够找出我的答案。这是一个onPhoneStatusChange插件,可以找到here!
神秘在于以下几点:
PluginResult res = new PluginResult(PluginResult.Status.OK, obj);
res.setKeepCallback(true);
success(res, callbackId);
答案 2 :(得分:1)
此问题的一般解决方案是让服务将响应存储到持久存储(如数据库)中,然后触发广播意图。然后在ServiceClient_plugin类中使用BroadcastReciever监听广播。这样您就不必继续轮询以查看数据是否已到达。
答案 3 :(得分:1)
您可以使用PluginResult
函数发送success()
,如下所示:
public PluginResult execute(String action, JSONArray data, String callbackId) {}
private BroadcastReceiver Wifi_Receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
MyClass.this.success(new PluginResult(PluginResult.Status.OK,"count"+count),callback);
}
}
此处callback
是callbackId
函数的execute()