2013-06-29 14 views
6

Sto provando a creare un servizio appiccicoso che è collegabile a (ho bisogno di eseguire operazioni potenzialmente asincrone in background su alcuni dati che il servizio contiene). Per fare questo, devo essere sicuro che onBind funzioni sempre dopo onStartCommand. C'è un modo per garantire questo?Android: come forzare onStartCommand() a essere chiamato prima su onBind()?

+1

"Ho bisogno di eseguire operazioni potenzialmente asincrone in background su alcuni dati che il servizio contiene" - che non richiede il binding. – CommonsWare

+0

Due anni dopo, ma ... La mia risposta potrebbe aiutare. Prova l'approccio IntentService. – Mauker

risposta

0

Secondo il docs:

Un servizio può essenzialmente di due tipi:

introduttiva
Un servizio è "avviato" quando un componente di applicazione (ad esempio un'attività) avvia chiamando startService().
Bound
Un servizio è "associato" quando un componente dell'applicazione si lega ad esso chiamando bindService(). [..] Un servizio associato viene eseguito solo fino al associato a un altro componente dell'applicazione. Più componenti possono collegarsi al servizio in una sola volta, ma quando tutti si separano, il servizio viene distrutto.

Per assicurarsi che onStartCommand() viene sempre eseguito prima onBind(), tenere l'invio di un nuovo intento al momento del servizio che si desidera associare ad esso. Questo perché qualsiasi new intent to the service will triggeronStartCommand(), quindi una chiamata a bindService() eseguirà il onBind().

+1

Il problema è che quando chiamo 'startService()' e quindi quasi immediatamente 'bindService()', a volte Android pianifica 'onBind()' prima di 'onStartCommand()'. – pstobiecki

+0

La terza forma di servizio è un ibrido. Si noti che oBind() può chiamare se stesso startService (self) –

1

Il punto è che non si deve chiamare sia startService() che bindService(). Se si desidera associare a un servizio, chiamare bindService(). Quando il servizio è connesso, viene chiamata l'implementazione di ServiceConnection.onServiceConnected(), che fornisce un IBinder al servizio. In genere, un servizio associato viene utilizzato come parte server di un'interfaccia client-server interna. Ti leghi al servizio, recuperi un IBinder che ti dà un handle per l'oggetto Service stesso, e poi usi l'handle del Servizio per passare dati o chiamare metodi nel Servizio.

I servizi associati sono quasi sempre utilizzati per la connessione tra processi (IPC).

+4

Questo è falso. Rileggi questo documento: http://developer.android.com/guide/components/services.html. In particolare questo paragrafo: sebbene questa documentazione generalmente discuti separatamente questi due tipi di servizi, il servizio può funzionare in entrambi i modi: può essere avviato (per essere eseguito a tempo indeterminato) e consentire anche l'associazione. Si tratta semplicemente di implementare un paio di metodi di callback: onStartCommand() per consentire ai componenti di avviarlo e onBind() per consentire l'associazione. INOLTRE, non è possibile utilizzare l'oggetto servizio per IPC, è necessario utilizzare un Messenger o AIDL. – d370urn3ur

+0

Perché questa è la risposta accettata ?? Questo è assolutamente sbagliato –

0

Per chiunque risolva problemi di salvataggio. Puoi chiamare il servizio di avvio nel metodo onBind.

@Override 
public IBinder onBind(Intent intent) { 
    //stars self 
    Intent myIntent = new Intent(this, Service.class); 
    startService(myIntent); 

    //TODO 
    return null; 
} 

Quindi è sufficiente verificare se il servizio è già avviato o meno e gestirlo.

+0

Non sono sicuro che questo risponda alla domanda, ma è buona informazione –

+1

Non penso che questa sia una buona idea –

7

In base alle proprie esigenze, probabilmente non è necessario eseguire il binding al numero Service. Quindi utilizzare un IntentService sarebbe sufficiente, in quanto questo servizio si interromperà da solo dopo il completamento del lavoro.

Tratto dalla documentazione:

IntentService è una classe base per i servizi che gestiscono asincrone richieste (espressi come Intenti) su richiesta. I client inviano le richieste tramite chiamate startService (Intent); il servizio viene avviato secondo necessità, gestisce ogni Intento a turno utilizzando un thread di lavoro e si arresta automaticamente a quando non ha più lavoro.

Un esempio di IntentService:

public class MyService extends IntentService { 

    @Override 
    protected void onHandleIntent(Intent intent) { 
     if (intent != null) { 
      // Do some work here, get Intent extras if any, etc. 
      // ... 
      // Once this method ends, the IntentService will stop itself. 
     } 
    } 
} 

Maggiori informazioni su come creare un IntentService può essere trovato here.

Questo può gestire le operazioni asincrone. E se hai bisogno di un feedback, che "spezzerà" la parte asincrona del requisito, potresti usare uno LocalBroadcastManager o come hai detto, puoi associare a questo Service. E poi di nuovo, dipende da cosa stai cercando di fare.

Dai documenti, hai due tipi di servizi.

introduttiva

Un servizio viene "ha iniziato" quando un componente di applicazione (come ad esempio attività ) avvia chiamando StartService(). Una volta avviato, un servizio può essere eseguito in background indefinitamente, anche se il componente che è stato avviato viene distrutto. Di solito, un servizio avviato esegue una singola operazione e non restituisce un risultato al chiamante. Ad esempio, lo potrebbe scaricare o caricare un file sulla rete. Al termine dell'operazione , il servizio dovrebbe interrompersi.

Bound

Un servizio è "legato" quando un componente dell'applicazione lega ad esso da chiamando bindService(). Un servizio associato offre un'interfaccia client-server che consente ai componenti di interagire con il servizio, inviare richieste , ottenere risultati e persino farlo attraverso i processi con la comunicazione interprocesso (IPC). Un servizio associato viene eseguito solo fino al associato a un altro componente dell'applicazione. Più componenti possono collegarsi al servizio in una sola volta, ma quando tutti si separano, il servizio viene distrutto.

Promemoria: È possibile avviare una Service attraverso startService() per farlo funzionare "a tempo indeterminato" e si legano ad essa chiamando onBind() tardi.

Intent it = new Intent(this, MyService.class); 
startService(it); // Start the service. 
bindService(it, this, 0); // Bind to it. 

Se si desidera eseguire semplicemente questo servizio per il tempo che il Activity è in esecuzione, si può solo chiamare onBind().

Intent it = new Intent(this, MyService.class); 
bindService(it, this, 0); // This will create the service and bind to it. 

Maggiori informazioni su "default" Service, come usarlo e la sua attuazione può essere trovato here.

Basta scegliere ciò che funziona meglio per il tuo caso d'uso, e sei a posto.

Problemi correlati