2011-10-24 18 views
8

Próbuję utworzyć wtyczkę do Phonegap (Android), która pozwala mojemu javascriptowi na wysyłanie i odbieranie wiadomości do/z usługi. Mój dokładny problem polega na tym, że ponieważ wiadomości zwracają asynchroniczne, nie mogę wysłać PluginResult do funkcji execute wtyczki.Jak uzyskać wiadomość zwrotną usługi Android z wtyczki phonegap

Jest to kod wtyczki:

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

} 

Od tej wtyczki prawdziwe kłopoty pochodzi z tej części kodu, który obsługuje wiadomości powrotne oraz powrotu wtyczki (która idzie do 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); 
     } 
     } 
    } 

Jedyne rozwiązanie, jakie przychodzi mi do głowy, to przechowywanie odpowiedzi w bazie danych lub zmiennej, a javascript powinien wykonać setInterval, aby nadal sprawdzać zmiany. Jednak nie bardzo lubię to rozwiązanie. Chciałbym użyć jakiejś funkcji wywołania zwrotnego, aby javascript wiedział, że wiadomość powróciła, ale nie mam pojęcia, jak to zrobić. Byłbym wdzięczny za każdą pomoc i pomysły.

Dziękuję Vlad

Odpowiedz

6

To może być późna odpowiedź, ale zacząłem pracować z wtyczką Cordova około 5 miesięcy po o i właśnie zobaczyłem twoje pytanie. Ponieważ nie wybrałeś poprawnej odpowiedzi, chciałem odpowiedzieć na twoje pytanie.

Zakładając, że masz proces asynchroniczny i masz słuchacza i metody, sukces i porażkę, możemy nazwać to onSuccess() i onFail(). Tak długo, jak wysyłasz komendę z pluginResult.setKeepCallback(true), proces pozostanie niezakończony, więc możesz przesłać dane o wynikach wtyczki później, gdy skończysz z procesem działającym w tle. Oto przykładowy wygląd.

@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

Ogólny Rozwiązaniem tego problemu jest posiadanie sklepu usługa odpowiedź do pamięci trwałej (jak bazy danych), a następnie wystrzelić intencję przekazu. Następnie wystarczy BroadcastReciever w klasie ServiceClient_plugin nasłuchujący transmisji. W ten sposób nie będziesz musiał sprawdzać, czy dane jeszcze dotarły.

+0

Dziękuję za szybką odpowiedź, twój BroadcastReciever odpowiedź doprowadzić mnie do pewnych przykładowych pluginów na github.com i rzeczywiście znalazłem to, czego szukałem tam. –

4

Odpowiedź na mój problem była w rzeczywistości w metodzie PluginResult i metodzie sukcesu. Znalazłem wtyczkę, która musiała stawić czoła temu samemu problemowi, aby pracować, iz tego kodu udało mi się wymyślić moją odpowiedź. Jest to wtyczka onPhoneStatusChange, którą można znaleźć pod adresem here!

Tajemnica tkwi w tych liniach:

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

można wysyłać PluginResult użyciu success() funkcję tak:

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

tutaj callback jest callbackId z execute() funkcji

Powiązane problemy