2011-12-23 9 views
34

Ho un servizio che è binded al contesto di applicazione in questo modo:Android: Come non associare in modo sicuro un servizio

getApplicationContext().bindService(
        new Intent(this, ServiceUI.class), 
        serviceConnection, 
        Context.BIND_AUTO_CREATE 
      ); 

protected void onDestroy() { 
      super.onDestroy();     
      getApplicationContext().unbindService(serviceConnection); 
     } 

Per qualche ragione, solo a volte il contesto dell'applicazione non si lega correttamente (non riesco a risolvere quella parte), ma in OnDestroy() faccio unbindservice che genera un errore

java.lang.IllegalArgumentException: Service not registered: tools.cdevice.Devices$mainServiceConnection. 

la mia domanda è: c'è un modo per chiamare unbindservice in modo sicuro o controllare se è già legato ad un servizio prima Disassocia esso?

Grazie in anticipo.

+0

controllo http: // StackOverflow.it/questions/1916253/bind-service-to-activity-in-android –

+0

L'ho già fatto prima ma questo non risolve il mio problema, diciamo solo che chiamo UnBindService senza chiamare BindService(), come gestisci l'errore senza l'applicazione FC? – 2ndlife

+0

Non potresti cogliere l'eccezione e andare avanti? – dragonroot

risposta

57

Prova questo:

boolean isBound = false; 
... 
isBound = getApplicationContext().bindService(new Intent(getApplicationContext(), ServiceUI.class), serviceConnection, Context.BIND_AUTO_CREATE); 
... 
if (isBound) 
    getApplicationContext().unbindService(serviceConnection); 

Nota:

Si dovrebbe usare lo stesso context per il legame di un servizio e non vincolante di un servizio. Se stai vincolando Servizio con getApplicationContext() quindi dovresti usare anche getApplicationContext.unbindService(..)

+1

Ho seguito la tua risposta e sto ancora ricevendo lo stesso errore. Risposta @Yury risolvere il problema. – VansFannel

+0

entrambe le risposte sono corrette: quella di Andrey Novikov e @Yury – Snicolas

+0

Mi sembra che questa soluzione possa perdere il servizio associato, perché ho appena scoperto che lo sbiadimento deve essere chiamato nello stesso contesto. Quindi testare in un contesto diverso potrebbe creare risultati strani avendo effettivamente associato due volte a un particolare servizio (se possibile?) – 3c71

7

Here è possibile trovare una buona spiegazione e codici sorgente su come lavorare con servizi associati. Nel tuo caso devi sostituire i metodi (onServiceConnected e onServiceDisconnected) dell'oggetto ServiceConnection. Quindi puoi semplicemente controllare la variabile mBound nel tuo codice.

+0

Temo che l'esempio dato sia per servizi locali, non servizi di elaborazione remota. –

+4

A differenza di quello locale, l'associazione ai servizi remoti ci darà la callback 'onServiceDisconnected()' se il processo del servizio di destinazione muore e 'onServiceConnected()' verrà nuovamente consegnato al riavvio. Se ci si basa su questi callback per il flag 'mBound', si otterrà una perdita di connessione del servizio se il tentativo di unbind è fatto tra' onServiceDisconnected() 'e' onServiceConnected() 'quando' mBound' sarebbe ' false'. –

+0

Per risolvere questo problema, non impostare mBound su false sotto onServiceDisconnected. E se è necessario tenere traccia degli stati connessi e disconnessi, magari introdurre un'altra variabile mConnected. –

4

Fare esattamente quello che Andrey Novikov ha proposto non ha funzionato per me. ho semplicemente sostituito:

getApplicationContext().unbindService(serviceConnection); 

Con:

unbindService(serviceConnection); 
+0

Che cos'è ** serviceConnection **? –

4

ho trovato ci sono due questioni. Tentativo di legare più di una volta e anche tentare di sciogliersi più di una volta.

Soluzione:

public class ServiceConnectionManager implements ServiceConnection { 

    private final Context context; 
    private final Class<? extends Service> service; 
    private boolean attemptingToBind = false; 
    private boolean bound = false; 

    public ServiceConnectionManager(Context context, Class<? extends Service> service) { 
     this.context = context; 
     this.service = service; 
    } 

    public void bindToService() { 
     if (!attemptingToBind) { 
      attemptingToBind = true; 
      context.bindService(new Intent(context, service), this, Context.BIND_AUTO_CREATE); 
     } 
    } 

    @Override 
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) { 
     attemptingToBind = false; 
     bound = true; 
    } 

    @Override 
    public void onServiceDisconnected(ComponentName componentName) { 
     bound = false; 
    } 

    public void unbindFromService() { 
     attemptingToBind = false; 
     if (bound) { 
      context.unbindService(this); 
      bound = false; 
     } 
    } 

} 
+2

Funziona, ma sembra davvero strano che tu debba mantenere "legato" manualmente - sembra che dovrebbe essere una variabile interna accessibile. –

+0

@DavidDoria Potrebbe sembra imbarazzante, ma in realtà è come Android mostrano come farlo: http://developer.android.com/guide/components/bound-services.html – ForceMagic

+0

Questa risposta ha funzionato per me, perché mi sono reso conto che ero , stupidamente, chiamando myService.unbindService (myServiceConnectionManager) invece di chiamare context.unbindService (...) –

0

Non sono sicuro su tutte le risposte di cui sopra, sembrava troppo complicato, mentre nessuno di questi si adatterebbe il problema che ho avuto.

Solo rilegatura/disassociazione una volta alla volta e il servizio era definitivamente associato al momento della chiamata unbind(). Non voglio perdere nulla, quindi mi sono semplicemente assicurato che stavo usando lo stesso contesto per le chiamate bind() e unbind() e che l'ho risolto in modo permanente! Fare qualcosa di simile:

any_context.getApplicationContext().bind(...); 

... 

another_context.getApplicationContext().unbind(...); 
0

penso che guide non è del tutto corretto come detto here Surya Wijaya Madjid. Perdite di memoria possono verificarsi quando il servizio associato è destryed e non ancora riconnesso.

Penso che sia necessario questo approccio:

Service mService; 

private final ServiceConnection mServiceConnection = new ServiceConnection() 
{ 
    boolean bound = false; 

    @Override 
    public void onServiceDisconnected(ComponentName name) 
    { 
     mService = null; 
    } 

    @Override 
    public void onServiceConnected(ComponentName name, IBinder service) 
    { 
     mService = ((MyService.ServiceBinder) service).getService(); 

     if (!bound) 
     { 
      // do some action - service is bound for the first time 
      bound = true; 
     } 
    } 
}; 

@Override 
public void onDestroy() 
{ 
    if (mService != null) 
    { 
     // do some finalization with mService 
    } 

    if (mServiceConnection.bound) 
    { 
     mServiceConnection.bound = false; 
     unbindService(mServiceConnection); 
    } 
    super.onDestroy(); 
} 

public void someMethod() 
{ 
    if (mService != null) 
    { 
     // to test whether Service is available, I have to test mService, not  mServiceConnection.bound 
    } 
} 
Problemi correlati