Vincular el servicio a la actividad en Android

90

Estoy tratando de escribir un reproductor multimedia simple que reproduzca audio en tiempo real usando RTSP. Tengo una actividad de GUI y un servicio que realiza la reproducción. Mi pregunta es cómo comunicarnos mejor entre la actividad y el servicio (por ejemplo, actualizar la GUI según el estado del reproductor).

Sé que puedo vincular el servicio a la actividad usando onBind (), pero si entiendo correctamente, esto detendrá el servicio si la actividad se cancela. Quiero continuar la reproducción incluso si el usuario sale de la actividad. ¿Existe alguna forma estándar o preferida de abordar este problema?

aspartamo
fuente

Respuestas:

154

"Si inicias un servicio de Android, startService(..)ese servicio seguirá ejecutándose hasta que lo invoques explícitamente stopService(..). Hay dos razones por las que el sistema puede ejecutar un servicio. Si alguien llama Context.startService(), el sistema recuperará el servicio (creándolo y llamando a su onCreate()método si necesario) y luego llamar a su onStartCommand(Intent, int, int)método con los argumentos proporcionados por el cliente. En este punto, el servicio continuará ejecutándose hasta que se llame Context.stopService()o stopSelf(). Tenga en cuenta que varias llamadas para Context.startService()no anidar (aunque dan como resultado múltiples llamadas correspondientes a onStartCommand()), por lo que no importa cuántas veces se inicie, un servicio se detendrá una vez Context.stopService()o stopSelf()se llamará; sin embargo, los servicios pueden usar sustopSelf(int) método para garantizar que el servicio no se detenga hasta que se hayan procesado las intenciones iniciadas.

Los clientes también pueden utilizar Context.bindService()para obtener una conexión persistente a un servicio. Esto también crea el servicio si aún no se está ejecutando (llamando onCreate()mientras lo hace), pero no llama onStartCommand(). El cliente recibirá el IBinderobjeto que el servicio devuelve de su onBind(Intent)método, lo que le permitirá volver a llamar al servicio. El servicio seguirá funcionando mientras se establezca la conexión (independientemente de que el cliente conserve una referencia en el Servicio IBinder). Por lo general, la IBinderdevolución es para una interfaz compleja que se ha escrito en AIDL.

Un servicio puede iniciarse y tener conexiones vinculadas a él. En tal caso, el sistema mantendrá el servicio en ejecución mientras se inicie o haya una o más conexiones con el Context.BIND_AUTO_CREATEindicador. Una vez que ninguna de estas situaciones se cumple, onDestroy()se llama al método del Servicio y el servicio se cancela efectivamente. Toda la limpieza (detener hilos, cancelar el registro de receptores) debe estar completa al regresar onDestroy()".

Schildmeijer
fuente
1
un poco de confusión: ¿Es cierto que si se destruye la actividad también se destruirá el servicio? ¿O ese servicio no se destruye solo si implemento mi propio AIDL? Lo pregunto porque cuando uso startService (especialmente en IntentService), el servicio se detiene cuando finaliza su trabajo en lugar de cuando la actividad muere. Entonces, ¿es cierto que si la actividad muere, entonces el servicio que está vinculado (exclusivamente) también muere?
Catedral Pillon
1
si está utilizando un servidor simple llamando a startService, el servicio no se detendrá hasta que llame a stopSelf () o stopService (). Y a continuación, si usa bindService, el servicio sí morirá si todos los componentes conectados / vinculados se destruyen.
Asif Mushtaq
1
@UnKnown Si el servicio se inicia usando startService (), entonces no importa si lo enlaza o desvincula, seguirá ejecutándose y solo puede destruirse llamando a stopService () o stopSelf (). Por lo tanto, incluso si se destruye la actividad que estaba vinculada al servicio, el servicio no se destruirá.
CopsOnRoad
¿Pueden ayudarme con esta pregunta? Stackoverflow.com/questions/51508046/…
Rajesh K
25

En primer lugar, dos cosas que debemos entender

Cliente

  • hace una solicitud a un servidor específico

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

aquí mServiceConnhay una instancia de ServiceConnectionclase (incorporada), en realidad es la interfaz que debemos implementar con dos métodos (el primero para la red conectada y la segunda red no conectada) para monitorear el estado de la conexión de red.

Servidor

  • Maneja la solicitud del cliente y hace una réplica propia que es privada solo para el cliente que envía la solicitud y esta réplica del servidor se ejecuta en un hilo diferente.

Ahora en el lado del cliente, ¿cómo acceder a todo el método del servidor?

  • servidor envía respuesta con IBind Object.so IBind object es nuestro controlador que accede a todos los métodos de servicio mediante el 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;
        }
    }
    

ahora cómo llamar al método que se encuentra en servicio

myservice.serviceMethod();

aquí myServiceestá el objeto y el serviceMethodemétodo en servicio. Y de esta manera se establece la comunicación entre cliente y servidor.

Hardik Gajera
fuente
10

traté de llamar

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

en consecuencia, podría crear un servicio fijo y vincularme a él. Tutorial detallado para el ejemplo de servicio enlazado .

M.Hefny
fuente
5

Existe un método llamado unbindService que tomará una ServiceConnection que habrá creado al llamar a bindService. Esto le permitirá desconectarse del servicio mientras lo deja en ejecución.

Esto puede suponer un problema cuando se vuelva a conectar, ya que probablemente no sepa si se está ejecutando o no cuando vuelva a iniciar la actividad, por lo que tendrá que considerarlo en su código de actividad.

¡Buena suerte!

vrutberg
fuente
-1

Esta es una respuesta sesgada, pero escribí una biblioteca que puede simplificar el uso de los servicios de Android, si se ejecutan localmente en el mismo proceso que la aplicación: https://github.com/germnix/acacia

Básicamente, usted define una interfaz anotada con @Service y su clase de implementación, y la biblioteca crea y vincula el servicio, maneja la conexión y el hilo de trabajo en 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>

Puede obtener una instancia del android.app.Service asociado para ocultar / mostrar notificaciones persistentes, usar su propio android.app.Service y manejar manualmente los subprocesos si lo desea.

alemán
fuente
-5

Si el usuario se retira, onDestroy()se llamará al método. Este método consiste en detener cualquier servicio que se utilice en la aplicación. Entonces, si desea continuar con el servicio incluso si el usuario se retira de la aplicación, simplemente borre onDestroy(). Espero que esto ayude.

Mira Febriani
fuente
Tendría que anular la función y eliminar la llamada predeterminada al onDestroy () de la superclase si su IDE crea una automáticamente. pero ¿por qué querrías hacer esto?
Riptyde4