2010-04-12 8 views
41

Attualmente dispongo di un servizio in Android che è un client VOIP di esempio in modo che sia in ascolto per i messaggi SIP e se ne riceve uno avvia una schermata Attività con componenti dell'interfaccia utente.Un modo più efficiente di aggiornare l'interfaccia utente dal servizio rispetto alle intenzioni?

Quindi i seguenti messaggi SIP determinano l'attività da visualizzare sullo schermo. Ad esempio se si tratta di una chiamata in arrivo, verrà visualizzato Rispondi o Rifiuta o una chiamata in uscita mostrerà una schermata di composizione.

Nel momento in cui utilizzo Intents per consentire all'attività di conoscere lo stato da visualizzare.

Un esempio è la seguente:


 Intent i = new Intent(); 
     i.setAction(SIPEngine.SIP_TRYING_INTENT); 
     i.putExtra("com.net.INCOMING", true); 
     sendBroadcast(i); 

     Intent x = new Intent(); 
     x.setAction(CallManager.SIP_INCOMING_CALL_INTENT); 
     sendBroadcast(x); 
     Log.d("INTENT SENT", "INTENT SENT INCOMING CALL AFTER PROCESSINVITE"); 

Così l'attività avrà un ricevitore trasmissione registrata per questi intenti e passerà il suo stato secondo l'ultimo intento che ha ricevuto.

codice di esempio come segue:


 SipCallListener = new BroadcastReceiver(){ 

      @Override 
      public void onReceive(Context context, Intent intent) { 
        String action = intent.getAction(); 

        if(SIPEngine.SIP_RINGING_INTENT.equals(action)){ 
         Log.d("cda ", "Got RINGING action SIPENGINE"); 
         ringingSetup(); 
        }   

        if(CallManager.SIP_INCOMING_CALL_INTENT.equals(action)){ 
         Log.d("cda ", "Got PHONE RINGING action"); 
         incomingCallSetup(); 
        } 
      } 
     }; 
     IntentFilter filter = new IntentFilter(CallManager.SIP_INCOMING_CALL_INTENT); 
     filter.addAction(CallManager.SIP_RINGING_CALL_INTENT); 
     registerReceiver(SipCallListener, filter); 

Questo funziona però sembra che non è molto efficiente, gli intenti otterrà sistema di trasmissione ampio e Intenti dover sparare per diversi stati sembra come potrebbe diventare inefficiente più devo aggiungere e aggiungere complessità.

Quindi mi chiedevo se c'è un modo diverso più efficiente e più pulito per fare questo?

C'è un modo per mantenere la trasmissione Intenti solo all'interno di un'applicazione?

Le richiamate sarebbero un'idea migliore? Se sì, perché e in che modo dovrebbero essere implementati?

risposta

52

UPDATE 2015:

Questa domanda/risposta ottiene ancora un po 'di attività, ma è più di 5 anni anni e le cose sono cambiate un bel po'. 5 anni fa, la risposta sotto era come l'avrei gestita. Più tardi ho scritto una soluzione di iniezione di dipendenza molto leggera che stavo usando da un po '(che ho citato nei commenti). Oggi risponderei a questa domanda usando Dagger e RxAndroid. Pugnale per iniettare una classe "mediatore" nel Servizio e in tutte le Attività che devono essere notificate, il Servizio sposterà l'aggiornamento di stato nella classe mediatore, e la classe mediatore esporrà un osservabile per le attività a consumare l'aggiornamento di stato (al posto del ricevitore broadcast dell'OP).

risposta originale

I Applicazione di solito sottoclasse e lasciare che la mia comunicazione in-app passare attraverso questa classe (o di avere un mediatore di proprietà del Application fare il lavoro ... a prescindere, essendo l'applicazione il punto di ingresso per il servizio di comunicare con). Ho un servizio vincolato che deve aggiornare anche l'interfaccia utente (molto più semplice della tua, ma la stessa idea) e in pratica dice all'app il suo nuovo stato e l'app può quindi passare queste informazioni in un modo o nell'altro attività attiva.Puoi anche mantenere un puntatore all'attività attualmente attiva (se ce n'è più di una) e decidere se aggiornare o meno semplicemente l'attività corrente, trasmettere l'intento di lanciare un'attività diversa, ignorare il messaggio, ecc. anche sottoclasse Attività e la tua nuova classe di base attività dirà all'Applicazione che è attualmente attiva in onResume e che è in pausa in onPause (per i casi in cui il tuo servizio è in esecuzione in background e tutte le attività sono in pausa).

EDIT:

In risposta al commento, ecco più specifiche.

Attualmente l'applicazione è composta prevalentemente da classi derivate da attività e derivate dal servizio. Intrinsecamente, si ottiene funzionalità da un'istanza della classe android.app.Application. Questo è dichiarato nel manifesto (per impostazione predefinita) con la seguente riga:

<application android:icon="@drawable/icon" android:label="@string/app_name"> 

L'elemento applicazione nel vostro manifest non utilizza l'attributo android: nome, in modo che solo crea un'istanza della android.app di default . Classe di applicazione per rappresentare il contesto applicativo globale.

Nelle mie app, creo una sottoclasse di Application (ApplicationEx, ad esempio) e comunico alla mia app tramite manifest che questa è la classe da istanziare come MY application context globale. Ad esempio:

<application 
    android:name="com.mycompany.myapp.app.ApplicationEx" 
    android:icon="@drawable/app_icon" 
    android:label="@string/app_name"> 

Ora è possibile aggiungere metodi a ApplicationEx per attività e servizi da utilizzare per comunicare. C'è sempre una singola istanza del contesto globale dell'applicazione, quindi questo è il tuo punto di partenza se qualcosa deve essere globale per la tua app.

Un secondo pezzo di questo è che invece di ricavare i miei servizi e attività da Servizio e Attività, creo una sottoclasse di ciascuno con un metodo getAppContext che esegue il valore restituito di getApplicationContext (che esiste già in entrambe queste classi perché derivano dal contesto) alla mia classe ApplicationEx.

Quindi ........

Detto questo, si aggiunge una proprietà CurrentActivity alla classe ApplicationEx di tipo di attività (o ActivityBase se sottoclasse come faccio io). Nel metodo onResume di ActivityBase, passate a ApplicationEx per impostare CurrentActivity su tale attività. Ora è possibile esporre i metodi su ApplicationEx per passare le informazioni direttamente all'attività corrente anziché affidarsi ai meccanismi Intent.

Quello è circa chiaro come posso farlo

+0

Ho letto il tuo post un paio di volte Rich e non sono sicuro di cosa intendi. Potresti fornire un link ad un esempio di come è stato fatto in quel modo? –

+4

Ho fornito ulteriori spiegazioni sopra ... fammi sapere se ne hai di più o se non è chiaro. – Rich

+0

Grazie per quel Rich, post eccellente! –

2

È possibile inviare intenti di trasmissione solo per la propria applicazione e non a livello di sistema con LocalBroadcastManager:

Helper per iscriversi e inviare le trasmissioni di intenti per oggetti locali nel tuo processo. Questo è ha una serie di vantaggi rispetto l'invio di trasmissioni globali con sendBroadcast (Intent):

Voi sapete che i dati che si sta trasmettendo non lascerà la vostra applicazione, quindi non hanno bisogno di preoccuparsi di perdite di dati privati.

Non è possibile che altre applicazioni inviino tali trasmissioni alla tua app, quindi non devi preoccuparti di avere buchi di sicurezza che possono sfruttare.

È più efficiente dell'invio di una trasmissione globale attraverso il sistema.

Tuttavia, mi raccomando comunque di andare con l'approccio Servizio e legare e parlare localmente tramite Handler quando necessario per aggiornare i componenti dell'interfaccia utente per l'efficienza.

Problemi correlati