Descripción general de los procesos y subprocesos

Cuando se inicia un componente de la aplicación y la aplicación no tiene ningún otro componente en ejecución, el sistema Android inicia un nuevo proceso de Linux para la aplicación con un solo subproceso de ejecución. De forma predeterminada, todos los componentes de la misma aplicación se ejecutan en el mismo proceso y subproceso. llamado subproceso main.

Si se inicia un componente de la aplicación y ya hay un proceso para esa aplicación, porque otro componente de la aplicación ya se inició, entonces el componente se inicie en el proceso y use el mismo subproceso de ejecución. Sin embargo, puedes organizar que componentes de tu aplicación para que se ejecuten en procesos separados, y puedes crear subprocesos para cualquier proceso.

En este documento, se analiza cómo funcionan los procesos y los subprocesos en una aplicación para Android.

Procesos

De forma predeterminada, todos los componentes de una aplicación se ejecutan en el mismo proceso y la mayoría de las aplicaciones no cambien esto. Sin embargo, si necesitas controlar qué procesos al que pertenece, puedes hacerlo en el archivo de manifiesto.

La entrada de manifiesto de cada tipo de elemento componente (<activity>, <service>, <receiver> y <provider>) admite un atributo android:process que puede especificar un el proceso en el que se ejecuta el componente. Puedes establecer este atributo para que cada componente se ejecute en su propio proceso o de modo que algunos componentes compartan un proceso y otros no.

También puedes establecer android:process para que los componentes de diferentes aplicaciones se ejecuten en la misma siempre que las aplicaciones compartan el mismo ID de usuario de Linux y estén firmadas con el los mismos certificados.

La <application> también admite un atributo android:process, que puedes usar para establecer una el valor predeterminado que se aplica a todos los componentes.

Android podría decidir cerrar un proceso en algún momento, cuando los recursos se que requieren otros procesos que están disponibles para el usuario de forma más inmediata. Aplicación componentes que se ejecutan en el proceso que se cierra. Se inicia un proceso de nuevo para esos componentes cuando haya trabajo que puedan hacer.

Al decidir qué procesos cerrar, el sistema Android pondera su importancia relativa para del usuario. Por ejemplo, cierra más rápido un proceso que aloja actividades que ya no están visibles en la pantalla, en comparación con un proceso que aloja actividades visibles. La decisión de si finalizar un proceso, por lo tanto, depende del estado de los componentes que se ejecutan en ese proceso.

Los detalles del ciclo de vida del proceso y su relación con los estados de la aplicación se analizan en Ciclo de vida de procesos y apps.

Subprocesos

Cuando se inicia una aplicación, el sistema crea un subproceso de ejecución para la aplicación, llamado subproceso principal. Este subproceso es muy importante, ya que se encarga de enviar eventos a los widgets adecuados de la interfaz de usuario, incluidos los eventos de dibujo. También se usa casi siempre, el subproceso en el que tu aplicación interactúa con los componentes desde el archivo android.widget del kit de herramientas de IU de Android android.view paquetes. Por este motivo, a veces el subproceso principal llamado subproceso de IU. Sin embargo, en circunstancias especiales, la principal no sea el de la IU. Para obtener más información, consulta Thread anotaciones.

El sistema no crea un subproceso separado para cada instancia de un componente. Todo los componentes que se ejecutan en el mismo proceso se crean en el subproceso de IU y las llamadas al sistema cada componente se envían desde ese subproceso. Por consiguiente, los métodos que responden al sistema devoluciones de llamada, como onKeyDown() para informar acciones del usuario, o un método de devolución de llamada de ciclo de vida, siempre se ejecuta en el subproceso de IU del proceso.

Por ejemplo, cuando el usuario toca un botón en la pantalla, el subproceso de IU de tu app distribuye el evento táctil al widget, que, a su vez, establece su estado presionado y publica una solicitud de invalidación en la fila de eventos. El subproceso de IU saca de la cola la solicitud y notifica al widget para que vuelva a dibujarla a sí mismo.

A menos que implementes tu aplicación correctamente, este modelo de un solo subproceso puede generar un rendimiento deficiente cuando la app realiza trabajo intensivo en respuesta a la interacción del usuario. Realizar operaciones largas en el subproceso de IU, como el acceso a la red o a la base de datos, bloquea toda la IU. Cuando el subproceso está bloqueado, no se pueden enviar eventos, incluidos los eventos de dibujo.

Desde la perspectiva del usuario, la aplicación no responde. Y lo que es peor, si el subproceso de IU se bloquea durante más de unos segundos, al usuario se le presenta la "aplicación respondiendo". (ANR). El usuario podría decidir salir de la aplicación o, incluso, desinstalarla. que la modifica.

Ten en cuenta que el kit de herramientas de la IU de Android no es seguro para los subprocesos. Así que no manipules la IU desde un subproceso de trabajo. Realiza toda la manipulación de la interfaz de usuario desde la IU. conversación. Hay dos reglas para el modelo de subproceso único de Android:

  1. No bloquees el subproceso de IU.
  2. No accedas al kit de herramientas de la IU de Android desde fuera del subproceso de IU.

Subprocesos de trabajo

Debido a este modelo de un solo subproceso, es fundamental que la capacidad de respuesta de tu la IU de tu aplicación de no bloquear el subproceso de IU. Si debes realizar operaciones que no son instantáneas, asegúrate de hacerlos en segundo plano por separado worker. Recuerda que no puedes actualizar la IU desde ningún subproceso que no sea el subproceso de IU, o subproceso principal.

Para ayudarte a seguir estas reglas, Android ofrece varias maneras de acceder al subproceso de IU desde otros conversaciones. En la siguiente lista, se incluyen métodos que pueden ser útiles:

En el siguiente ejemplo, se usa View.post(Runnable):

Kotlin

fun onClick(v: View) {
    Thread(Runnable {
        // A potentially time consuming task.
        val bitmap = processBitMap("image.png")
        imageView.post {
            imageView.setImageBitmap(bitmap)
        }
    }).start()
}

Java

public void onClick(View v) {
    new Thread(new Runnable() {
        public void run() {
            // A potentially time consuming task.
            final Bitmap bitmap =
                    processBitMap("image.png");
            imageView.post(new Runnable() {
                public void run() {
                    imageView.setImageBitmap(bitmap);
                }
            });
        }
    }).start();
}

Esta implementación es segura para subprocesos, ya que la operación en segundo plano se realiza desde un subproceso independiente. mientras que ImageView siempre se manipula desde el subproceso de IU.

Sin embargo, a medida que aumenta la complejidad de la operación, este tipo de código difíciles de mantener. Para manejar interacciones más complejas con un subproceso de trabajo, puedes considerar con un Handler en tu subproceso de trabajo para procesar los mensajes enviados desde el subproceso de IU. Para obtener una explicación completa sobre cómo programar el trabajo en subprocesos en segundo plano y comunicarse con el subproceso de IU, consulta Descripción general del trabajo en segundo plano.

Métodos seguros para subprocesos

En algunas situaciones, los métodos que implementas reciben llamadas desde más de un subproceso. por lo tanto, se deben escribir de modo que sean seguros para subprocesos.

Esto es particularmente cierto para los métodos que se pueden llamar de manera remota, como los métodos en un servicio vinculado. Cuando se recibe una llamada en un implementado en una IBinder se origina en el mismo proceso en el que Se está ejecutando IBinder y el método se ejecuta en el subproceso del llamador. Sin embargo, cuando la llamada se origina en otro proceso, el método se ejecuta en un subproceso elegido un grupo de subprocesos que el sistema mantiene en el mismo proceso que IBinder. No se ejecuta en el subproceso de IU del proceso.

Por ejemplo, mientras la disponibilidad Se llama al método onBind() desde el subproceso de IU de la del servicio, los métodos implementados en el objeto que muestra onBind(), como un que implementa métodos de llamada de procedimiento remoto (RPC) y se llama desde subprocesos. en la piscina. Debido a que un servicio puede tener más de un cliente, más de un subproceso de grupo puede interactuar el mismo método IBinder al mismo tiempo, por lo que los métodos IBinder deben ser implementar para que sean seguros para los subprocesos.

Asimismo, un proveedor de contenido puede recibir solicitudes de datos que se originen en otros procesos. ContentResolver y ContentProvider ocultan los detalles de cómo se administra la comunicación entre procesos (IPC), pero los métodos ContentProvider que responden a esas solicitudes (los métodos query(), insert(), delete(), update(), y getType(), son se llama desde un grupo de subprocesos en el proceso del proveedor de contenido, no desde la IU para el proceso. Como se puede llamar a estos métodos desde cualquier cantidad de subprocesos en el al mismo tiempo, estas también se deben implementar para que sean seguras para los subprocesos.

Comunicación entre procesos

Android ofrece un mecanismo para IPC mediante RPC, en el que una actividad o cualquier otra aplicación llama a un método. pero se ejecuta de forma remota en otro proceso, y cualquier resultado se devuelve al llamador. Esto implica desglosar una llamada de método y sus datos a un nivel en el que el sistema operativo entenderlos, transmitiéndolos desde el proceso local y el espacio de direcciones al proceso remoto y espacio de direcciones y, luego, volver a ensamblar y reproducir la llamada allí.

Luego, los valores que se devuelven se transmiten en la dirección opuesta. Android proporciona todo el código para realizar estas IPC para que puedas enfocarte en definir e implementar la interfaz de programación de RPC.

Para realizar una IPC, tu aplicación debe vincularse a un servicio con bindService(). Para obtener más información, consulta la Descripción general de los servicios.