2011-10-24 8 views
8

Sto cercando di creare un plug-in per PhoneGap (Android) che permetta al mio javascript di inviare e ricevere messaggi da/per un servizio. Il mio problema esatto è che, poiché i messaggi ritornano asincroni, non posso inviare PluginResult alla funzione di esecuzione del plugin.Come ottenere un messaggio di risposta di servizio Android da un plug-in PhoneGap

Questo è il codice del plugin:

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(); 
    } 
} 

} 

Da questo plugin il vero problema viene fornito con questa parte del codice, che gestisce i messaggi di ritorno e il ritorno plug-in (che va al 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); 
     } 
     } 
    } 

L'unica soluzione che posso pensare è memorizzare la risposta in un database o in una variabile e fare in modo che il javascript esegua un setInterval per continuare a controllare le modifiche. Comunque non mi piace molto questa soluzione. Vorrei usare una sorta di funzione di callback per far sapere al javascript che il messaggio è tornato, ma non ho idea di come. Apprezzerei molto ogni aiuto e idee.

Grazie, Vlad

risposta

6

Questo potrebbe essere un risposta tardiva, ma ho iniziato a lavorare con Cordova Plugin circa 5 mesi prima o e ho appena visto la tua domanda. Dal momento che non hai scelto la risposta corretta, volevo rispondere alla tua domanda.

Supponendo che si disponga di un processo asincrono e si disponga di un listener e dei metodi, esito positivo e negativo, è possibile chiamarlo onSuccess() e onFail(). Finché invii true con pluginResult.setKeepCallback(true), il processo rimarrà incompleto, quindi puoi inviare i dati dei risultati del plug-in in un secondo momento quando hai finito con il processo in background. Ecco un esempio dai un'occhiata.

@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

La soluzione generica a questo problema è quello di avere il servizio di archiviazione della risposta in memoria persistente (come un database) e poi sparare un intento trasmissione. Quindi basta che un BroadcastReciever nella classe ServiceClient_plugin ascolti la trasmissione. In questo modo non devi continuare a sondare per vedere se i dati sono arrivati ​​ancora.

+0

Grazie per la rapida risposta, la risposta di BroadcastReciever mi ha portato ad alcuni plug-in di esempio su github.com e ho effettivamente trovato quello che stavo cercando lì. –

4

La risposta al mio problema era in realtà l'oggetto PluginResult e il metodo di successo. Ho trovato un plugin che ha dovuto affrontare lo stesso problema per funzionare, e da questo codice sono stato in grado di capire la mia risposta.Questo è un plugin onPhoneStatusChange, che può essere trovato here!

Il mistero risiede in queste righe:

PluginResult res = new PluginResult(PluginResult.Status.OK, obj); 
res.setKeepCallback(true); 
success(res, callbackId); 
1

è possibile inviare PluginResult usando success() funzione come questa:

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

qui callback è callbackId di execute() funzione

Problemi correlati