如何从phonegap插件获取android服务返回消息

时间:2011-10-24 16:35:39

标签: java javascript android asynchronous cordova

我正在尝试为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知道消息已经返回,但我不知道如何。我非常感谢任何帮助和想法。

谢谢你, 维拉德

4 个答案:

答案 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);
    }
}

此处callbackcallbackId函数的execute()

相关问题