2015-02-16 10 views
7

Sto implementando il servizio Paho MQTT Android all'interno di un'applicazione che sto sviluppando. Dopo aver testato l'applicazione di esempio fornita da Paho, ho scoperto che ci sono alcune cose che vorrei cambiare.Paho MQTT Servizio Android Numero

https://eclipse.org/paho/clients/android/

Il servizio applicazioni sembra spegnere una volta che l'applicazione è completamente chiusa. Vorrei mantenere il servizio in esecuzione anche dopo la chiusura dell'applicazione nel caso in cui arrivino altri messaggi. Sto anche cercando un modo per aprire l'applicazione a un'attività specifica una volta ricevuto un nuovo messaggio.

Ecco uno dei callback che viene chiamato quando arriva un messaggio, ho cercato di implementare un semplice startActivity per aprire una specifica attività, ma non funziona se l'applicazione è chiusa /non è più in esecuzione.

Se qualcuno ha lavorato con il servizio Android PAHO MQTT, Esiste un modo specifico per impedire l'interruzione del servizio quando l'applicazione viene chiusa e come posso riaprire l'applicazione quando arriva un messaggio?

/** 
    * @see org.eclipse.paho.client.mqttv3.MqttCallback#messageArrived(java.lang.String, 
    *  org.eclipse.paho.client.mqttv3.MqttMessage) 
    */ 
    @Override 
    public void messageArrived(String topic, MqttMessage message) throws Exception { 

    // Get connection object associated with this object 
    Connection c = Connections.getInstance(context).getConnection(clientHandle); 

    // create arguments to format message arrived notifcation string 
    String[] args = new String[2]; 
    args[0] = new String(message.getPayload()); 
    args[1] = topic + ";qos:" + message.getQos() + ";retained:" + message.isRetained(); 

    // get the string from strings.xml and format 
    String messageString = context.getString(R.string.messageRecieved, (Object[]) args); 

    // create intent to start activity 
    Intent intent = new Intent(); 
    intent.setClassName(context, "org.eclipse.paho.android.service.sample.ConnectionDetails"); 
    intent.putExtra("handle", clientHandle); 

    // format string args 
    Object[] notifyArgs = new String[3]; 
    notifyArgs[0] = c.getId(); 
    notifyArgs[1] = new String(message.getPayload()); 
    notifyArgs[2] = topic; 

    // notify the user 
    Notify.notifcation(context, context.getString(R.string.notification, notifyArgs), intent, 
     R.string.notifyTitle); 

    // update client history 
    c.addAction(messageString); 

    Log.e("Message Arrived", "MESSAGE ARRIVED CALLBACK"); 

    // used to open the application if it is currently not active 
    Intent i = new Intent(context, ConnectionDetails.class); 
    i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
    i.putExtra("handle", clientHandle); 
    context.startActivity(i); 


    } 
+1

Qualche possibilità sei riuscito a risolvere? –

+0

Purtroppo no. Mi sono trasferito a lavorare con un esempio diverso. Pubblicherò una soluzione se la trovo. –

+0

Ok, grazie. –

risposta

2

So che questa è una risposta tardiva a questa domanda, ma mi piacerebbe condividere ciò che ho fatto in quanto potrebbe aiutare qualcuno.

Ho creato il mio Service per gestire la connessione al broker e mantenere sempre una singola istanza connessa per dispositivo Android.

Ribadendo le caratteristiche della soluzione:

caratteristiche chiave di questa soluzione:

  1. Service gestisce una singola istanza finché è vivo.
  2. Se il servizio viene interrotto, Android lo riavvia (perché START_STICKY)
  3. Il servizio può essere avviato all'avvio del dispositivo.
  4. Il servizio viene eseguito in background ed è sempre connesso per ricevere notifiche.
  5. Se il servizio è attivo, chiamando nuovamente startService(..) si attiverà il suo onStartCommand(). In questo metodo, controlliamo semplicemente se questo client è connesso al broker e ci si connette/ricollega se necessario.

Scopri i pienamente dettagliata risposta here.

5

Se si chiude la vostra applicazione utilizzando il task manager non credo che questo è possibile in quanto "pienamente chiusura" l'applicazione fermerà anche eventuali servizi in esso contenuti. Anche se il servizio è avviato "appiccicoso", non viene riavviato sul mio dispositivo. Se chiudi l'app facendo scorrere il dito sulle attività recenti, il servizio rimane in esecuzione. Vedi qui per maggiori informazioni: Killing android application from task manager kills services started by app

Tuttavia, penso che l'altro problema è anche se il servizio è ancora in esecuzione l'applicazione contiene gli oggetti di richiamata che vengono richiamati dal servizio. Se l'applicazione non è più in esecuzione, la callback non esiste più e quindi non viene mai chiamata.

Ecco una vista di alto livello di come ho implementato questo. Questo è stato in esecuzione in produzione per alcuni mesi, ma sfortunatamente non possiedo il codice e non posso pubblicarlo.

  • ho creato un oggetto Singleton che ospita il MQTTService/mqttAndroidClient. Ciò espone metodi pubblici per connettersi/disconnettersi e contiene l'oggetto MqttCallback utilizzato per ricevere i messaggi. Gestisce anche la connessione persa e riprova i meccanismi necessari. Questa è la parte più difficile ma non posso postarla qui.
  • ho creato un oggetto Application, collega in onCreate() e chiudere la connessione in onTerminate()
  • ho registrato un BroadcastReceiver che ottiene l'azione BOOT_COMPLETED che risiede nell'oggetto Application, ha un'implementazione vuoto ma gira l'applicazione in modo il servizio mqtt si connette all'avvio.

Questo elimina la necessità di eseguire qualsiasi attività per ricevere un messaggio. Sembra anche resiliente contro la chiusura dell'applicazione, ad eccezione del fatto che "chiudi forzatamente" nelle impostazioni dell'applicazione. Questo succede da quando l'utente ha scelto esplicitamente di chiuderlo.

+0

Sono interessato alla soluzione. Ma hai detto: "Se chiudi l'app facendo scorrere il dito sulle attività recenti, il servizio rimane in esecuzione". Non penso che rimanga in esecuzione (almeno non nel modo in cui dovrebbe). Nessun messaggio viene ricevuto in seguito (nessuna notifica, niente). Se si riavvia l'applicazione, i messaggi inviati a questi argomenti a cui si è iscritti, vengono persi. :( –

+1

Ho aggiornato la mia risposta con ulteriori dettagli Mi dispiace non posso pubblicare il codice ma spero che questo ti dia un'idea di cosa sia coinvolto –

7

Mentre questa non sembra una soluzione completa al problema, inserirò la soluzione alternativa nel caso in cui aiuti qualcuno.

Per me il problema inizia quando l'utente fa scorrere l'app fuori dall'elenco delle app recenti.Come già detto, here un'azione non solo uccide l'attività, ma uccide l'intero processo, incluso lo MqttService. Quindi, come indicato nel thread, Android riconosce che il servizio deve essere riavviato e pianifica un riavvio del servizio ucciso. Tuttavia, questo non implica il ripristino della connessione poiché tutte le connessioni erano legate all'attività.

Quindi, a meno che non si trovi un modo per eliminare il problema di interruzione del servizio, si è certi di perdere la connessione con il broker quando l'utente decide di eliminare l'app.

Questa non è la fine del mondo, tuttavia, poiché possiamo semplicemente riconnetterci dopo aver perso la connessione. Il problema è che questa volta non abbiamo un'attività per fare l'azione desiderata. Devi modificare il codice sorgente della libreria dei servizi di Paho Android o, in un modo molto più semplice, quello che ho fatto è stato creare un altro servizio.

Tutte le connessioni si svolgeranno in questo nuovo servizio e tutte le attività che desiderano connettersi devono comunicare con questo servizio. Il vantaggio di questo è che possiamo rendere il servizio appiccicoso e anche se l'utente fa scorrere la nostra app e la uccide, si riavvierà immediatamente e potremo recuperare semplicemente ricollegando.

Quindi, come una dimostrazione con questo semplice servizio:

public class MessagingService extends Service { 
    private static final String TAG = "MessagingService"; 
    private MqttAndroidClient mqttClient; 
    String deviceId; 



    @Override 
    public void onCreate() { 
    } 
    private void setClientID() { 
     WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); 
     WifiInfo wInfo = wifiManager.getConnectionInfo(); 
     deviceId = wInfo.getMacAddress(); 
     if (deviceId == null) { 
      deviceId = MqttAsyncClient.generateClientId(); 
     } 
    } 

    public class MsgBinder extends Binder { 
     public MsgServ getService() { 
      return MsgServ.this; 
     } 
    } 

    public void doConnect(){ 
     // Using some of the Paho sample app classes 
     String server = ConfigClass.BROKER_URI; 
     MemoryPersistence mem = new MemoryPersistence(); 
     mqttClient = new MqttAndroidClient(this,ConfigClass.BROKER_URI,deviceId,mem); 
     MqttConnectOptions conOpt = new MqttConnectOptions(); 
     String clientHandle = server + deviceId; 
     Connection con = new Connection(clientHandle, deviceId, ConfigClass.BROKER_ADDRESS, 
             ConfigClass.BROKER_PORT, this, mqttClient, false); 
     conOpt.setCleanSession(false); 
     conOpt.setConnectionTimeout(ConfigClass.CONN_TIMEOUT); 
     conOpt.setKeepAliveInterval(ConfigClass.CONN_KEEPALIVE); 
     conOpt.setUserName("testclient"); 
     conOpt.setPassword("password".toCharArray()); 
     String[] actionArgs = new String[1]; 
     actionArgs[0] = deviceId; 
     final ActionListener callback = 
       new ActionListener(this, ActionListener.Action.CONNECT, clientHandle, 
            actionArgs); 
     mqttClient.setCallback(new MqttCallbackHandler(this, clientHandle)); 
     mqttClient.setTraceCallback(new MqttTraceCallback()); 
     con.addConnectionOptions(conOpt); 
     Connections.getInstance(this).addConnection(con); 
     try { 
      mqttClient.connect(conOpt, null, callback); 
      Log.d("Con", "Connected"); 
     } catch (MqttException e) { 
      Log.d("Con", "Connection failed"); 
      e.printStackTrace(); 
     } 
    } 

    @Override 
    public IBinder onBind(Intent intent) { 
     return null; 
    } 

    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 
     doConnect(); 
     return START_STICKY; 
    } 

} 

Log di server:

1433455371: New client connected from 192.168.2.5 as ed:0a:2b:56:b5:45 (c0, k30, u'testclient'). 
1433455371: Sending CONNACK to ed:0a:2b:56:b5:45 (1, 0) 
1433455375: Socket error on client ed:0a:2b:56:b5:45, disconnecting. 
1433455377: New connection from 192.168.2.5 on port 1883. 
1433455377: Client ed:0a:2b:56:b5:45 disconnected. 
1433455377: New client connected from 192.168.2.5 as ed:0a:2b:56:b5:45 (c0, k30, u'testclient'). 
1433455377: Sending CONNACK to ed:0a:2b:56:b5:45 (1, 0) 

Come si può vedere, non appena chiudo l'applicazione e il servizio viene ucciso , riavvia ricollega e ottiene mantenuta-in vita trova solo dopo. Da qui, dovresti essere in grado di fare il resto. Forse creando una notifica con il tuo messaggio appena arrivato che aprirà l'app. Ricorda solo di fare tutto nel nuovo servizio che è garantito per mantenere una connessione.

+0

Ti dispiacerebbe condividere un esempio pienamente funzionante (forse su github)? – Jdruwe

+0

Grazie, ho usato questo design per aggirare il problema delle connessioni/abbonamenti persi, ma ora nelle attività dell'app devo interagire con il servizio per pubblicare materiale, come posso andare a questo proposito? –

+0

@inkalimeva Vedi [Come comunicare il servizio Android con l'attività] (http://stackoverflow.com/a/2463746/777510) –

1

Penso che Eclipse Paho porti tutto il necessario per farlo. Posso scorrere la mia app e il mio servizio è in esecuzione. Per maggiori dettagli guarda la mia risposta al Paho MQTT Android service wake up activity

Spero che ti possa aiutare.