Vincular serviço à atividade no Android

90

Estou tentando escrever um reprodutor de mídia simples que reproduz streaming de áudio usando RTSP. Eu tenho uma atividade de GUI e um serviço que executa a reprodução. Minha pergunta é como se comunicar melhor entre a atividade e o serviço (por exemplo, atualizando a GUI com base no estado do player).

Sei que posso vincular o serviço à atividade usando onBind (), mas se bem entendi, isso interromperá o serviço se a atividade for interrompida. Desejo continuar a reprodução mesmo que o usuário saia da atividade. Existe alguma forma padrão ou preferencial de lidar com esse problema?

aspartame
fonte

Respostas:

154

"Se você iniciar um serviço android com startService(..)esse serviço permanecerá em execução até que você invoque explicitamente stopService(..). Há dois motivos pelos quais um serviço pode ser executado pelo sistema. Se alguém chamar Context.startService(), o sistema irá recuperar o serviço (criando-o e chamando seu onCreate()método se necessário) e, em seguida, chamar seu onStartCommand(Intent, int, int)método com os argumentos fornecidos pelo cliente. Nesse ponto, o serviço continuará em execução até Context.stopService()ou stopSelf()seja chamado. Observe que várias chamadas para Context.startService()não se aninham (embora resultem em várias chamadas correspondentes para onStartCommand()), portanto, não importa quantas vezes ele seja iniciado, um serviço será interrompido uma vez Context.stopService()ou stopSelf()chamado; no entanto, os serviços podem usar seusstopSelf(int) método para garantir que o serviço não seja interrompido até que os intents iniciados tenham sido processados.

Os clientes também podem usar Context.bindService()para obter uma conexão persistente com um serviço. Da mesma forma, isso cria o serviço, se ainda não estiver em execução (chamando onCreate()ao fazer isso), mas não chama onStartCommand(). O cliente receberá o IBinderobjeto que o serviço retorna de seu onBind(Intent)método, permitindo que o cliente faça chamadas de volta para o serviço. O serviço permanecerá em execução enquanto a conexão for estabelecida (independentemente de o cliente manter ou não uma referência no serviço IBinder). Normalmente, o IBinderretornado é para uma interface complexa que foi escrita em AIDL.

Um serviço pode ser iniciado e ter conexões vinculadas a ele. Nesse caso, o sistema manterá o serviço em execução, desde que seja iniciado ou haja uma ou mais conexões com o Context.BIND_AUTO_CREATEsinalizador. Assim que nenhuma dessas situações for mantida, o onDestroy()método do serviço é chamado e o serviço é encerrado efetivamente. Toda a limpeza (interromper threads, cancelar o registro de receptores) deve ser concluída ao retornar de onDestroy(). "

Schildmeijer
fonte
1
um pouco de confusão: É verdade que se a atividade for destruída o serviço também será destruído? Ou esse serviço não é destruído apenas se eu implementar meu próprio AIDL? Estou perguntando porque quando eu uso startService (especialmente em IntentService), o serviço para quando seu trabalho é concluído, e não quando a atividade termina. Portanto, é verdade que, se a atividade morrer, o serviço vinculado (exclusivamente) também morrerá?
Catedral Pillon
1
se você estiver usando um servidor simples chamando startService, o serviço não parará até que você chame stopSelf () ou stopService (). E no próximo, se você usar bindService, o serviço yes morrerá se todos os componentes conectados / vinculados forem destruídos.
Asif Mushtaq
1
@UnKnown Se o serviço for iniciado usando startService (), não importa se você vinculá-lo ou desvinculá-lo, ele continuará em execução e só poderá ser destruído chamando stopService () ou stopSelf (). Portanto, mesmo que a atividade vinculada ao serviço seja destruída, o serviço não será destruído.
CopsOnRoad
Você pode me ajudar com esta questão stackoverflow.com/questions/51508046/…
Rajesh K
25

Em primeiro lugar, 2 coisas que precisamos entender

Cliente

  • faz um pedido a um servidor específico

    bindService(new 
        Intent("com.android.vending.billing.InAppBillingService.BIND"),
            mServiceConn, Context.BIND_AUTO_CREATE);`

aqui mServiceConnestá um exemplo deServiceConnection classe (embutida), é na verdade a interface que precisamos implementar com dois métodos (1ª para rede conectada e 2ª não conectada) para monitorar o estado da conexão de rede.

Servidor

  • Ele lida com a solicitação do cliente e faz sua própria réplica, que é privada apenas para o cliente que envia a solicitação e essa réplica do servidor é executada em um thread diferente.

Agora do lado do cliente, como acessar todos os métodos do servidor?

  • servidor enviar resposta com IBind Object.so O objeto IBind é nosso manipulador que acessa todos os métodos de serviço usando o operador (.).

    MyService myService;
    public ServiceConnection myConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder binder) {
            Log.d("ServiceConnection","connected");
            myService = binder;
        }
        //binder comes from server to communicate with method's of 
    
        public void onServiceDisconnected(ComponentName className) {
            Log.d("ServiceConnection","disconnected");
            myService = null;
        }
    }

agora como chamar o método que está em serviço

myservice.serviceMethod();

aqui myServiceestá o objeto e o serviceMethodemétodo em serviço. E desta forma a comunicação é estabelecida entre o cliente e o servidor.

Hardik Gajera
fonte
10

eu tentei ligar

startService(oIntent);
bindService(oIntent, mConnection, Context.BIND_AUTO_CREATE);

consequentemente, eu poderia criar um serviço fixo e vincular a ele. Tutorial detalhado para exemplo de serviço vinculado .

M.Hefny
fonte
5

Há um método chamado unbindService que usará um ServiceConnection que você criou ao chamar bindService. Isso permitirá que você se desconecte do serviço e ainda o deixe em execução.

Isso pode representar um problema quando você se conectar a ele novamente, já que provavelmente não sabe se ele está em execução ou não quando inicia a atividade novamente, então você terá que considerar isso em seu código de atividade.

Boa sorte!

Vrutberg
fonte
-1

Esta é uma resposta tendenciosa, mas escrevi uma biblioteca que pode simplificar o uso de serviços Android, se eles forem executados localmente no mesmo processo que o aplicativo: https://github.com/germnix/acacia

Basicamente, você define uma interface anotada com @Service e sua classe de implementação, e a biblioteca cria e vincula o serviço, lida com a conexão e o thread de trabalho em segundo plano:

@Service(ServiceImpl.class)
public interface MyService {
    void doProcessing(Foo aComplexParam);
}

public class ServiceImpl implements MyService {
    // your implementation
}

MyService service = Acacia.createService(context, MyService.class);
service.doProcessing(foo);

<application
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme">
    ...
    <service android:name="com.gmr.acacia.AcaciaService"/>
    ...
</application>

Você pode obter uma instância do android.app.Service associado para ocultar / mostrar notificações persistentes, usar seu próprio android.app.Service e manipular manualmente o threading, se desejar.

alemão
fonte
-5

Se o usuário desistir, o onDestroy()método será chamado. Este método é parar qualquer serviço que é usado no aplicativo. Portanto, se quiser continuar o serviço mesmo que o usuário saia do aplicativo, apenas apague onDestroy(). Espero esta ajuda.

Mira Febriani
fonte
Você teria que substituir a função e excluir a chamada padrão para onDestroy () da superclasse se seu IDE criar uma automaticamente. mas por que você iria querer fazer isso?
Riptyde4