Android Framework-Optimización de proceso/hilo y memoria de programa de Android

Procesos y subprocesos de Android

Proceso (Process) es una instancia en ejecución de un programa para distinguirlo del concepto estático de "programa"; mientras que hilo (Thread) es la unidad básica de programación de la CPU.
¿Cuáles son los conceptos de programas y procesos en Android?
El principal punto de entrada de una aplicación es generalmente la función principal, que básicamente se ha convertido en una especificación para el desarrollo del programa: es el "origen de todo". El trabajo de la función main() también es el mismo. El resumen es el siguiente:
Inicialización
Por ejemplo, en el entorno Windows, suele ser necesario crear una ventana, solicitar recursos del sistema, etc.
Ingrese a un ciclo infinito
y procese varios eventos en el ciclo hasta que finalice el proceso.
Este modelo es un corolario de los sistemas de software "controlados por eventos" y, por lo tanto, existe en casi cualquier sistema operativo y lenguaje de programación.
Tome AndroidManifest.xml como ejemplo:

<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com. 
android.launchperf">
<application android:label="Launch Performance">
 <activity android:name="SimpleActivity" android:label="Simple
Activity">
 <intent-filter>
 <action android:name="android.intent.action.MAIN" />
 <category android:name="android.intent.category.DEFAULT" />
 </intent-filter>
 </activity>

Como puede ver, hay una etiqueta llamada <aplicación> alrededor de la actividad. En otras palabras, los cuatro componentes principales son solo las "partes" de la "aplicación".
Cree automáticamente una actividad y luego establezca un punto de interrupción en el método onCreate,
inserte la descripción de la imagen aquí
luego, cuando comience la actividad, ¿cuántos subprocesos se generarán (solo hay un subproceso principal)? como muestra la imagen.
inserte la descripción de la imagen aquí
Un programa de actividad creado por un asistente sin ninguna función real tiene tres subprocesos Además del subproceso principal con el que estamos más familiarizados (es decir, Subproceso [<1> principal] en la figura), hay dos subprocesos de enlace. ZygoteInit inicia el subproceso principal y, finalmente, ejecuta la función onCreate() de la propia actividad después de una serie de llamadas. El hilo principal creado por Zygote for Activity es ActivityThread:

 SamplingProfilerIntegration.start();
 CloseGuard.setEnabled(false);
 Process.setArgV0("<pre-initialized>");
 Looper.prepareMainLooper(); /*只有主线程才能调用这个函数,普通线程应该使用prepare(),
 */
 if (sMainThreadHandler == null) {
    
    
 sMainThreadHandler = new Handler(); /*主线程对应的Handler*/
 }
 ActivityThread thread = new ActivityThread(); /*这个main()是static的,因此在这里需要创建一个实例*/
 thread.attach(false); /*Activity是有界面显示的,这个函数将与WindowManagerService
 建立联系。*/Looper.loop(); /*主循环开始*/
 throw new RuntimeException("Main thread loop
unexpectedly exited");/*如果程序运 行到这里,说明退出了上面的Looper循环*/
 }

El servicio también se almacena en ActivityThread, y el proceso de inicio es básicamente el mismo que el de Activity.
Al iniciar el Servicio, también se requiere el apoyo de dos subprocesos Binder.

Para los cuatro componentes principales definidos en el mismo AndroidManifest.xml, a menos que se especifique lo contrario (, todos se ejecutan en el mismo proceso (y todos los eventos son manejados por el subproceso principal). Conclusión: 1. Los cuatro componentes principales no son programas
(
proceso ), pero solo sus "partes".
2. Después de que se inicie la aplicación, se creará el subproceso principal ActivityThread.
3. Los componentes en el mismo paquete se ejecutarán en el mismo espacio de proceso.
4. Componentes en diferentes paquetes Puede ejecutarse en un procesar el espacio de cierta manera
5. Después de iniciar una aplicación de Actividad, habrá al menos 3 subprocesos: un subproceso principal y dos subprocesos Binder.

Manejador, MessageQueue, Runnable, Looper

Un estudio preliminar sobre el concepto de
inserte la descripción de la imagen aquí
diagrama de relaciones Runnable, Message, MessageQueue, Looper y Handler
Runnable y Message se pueden insertar en una MessageQueue para formar una colección
inserte la descripción de la imagen aquí
Tenga en cuenta que, en general, un determinado tipo de MessageQueue solo puede guardar el mismo tipo de Objeto. En la figura, solo los mezclamos en el mismo MessageQueue para facilitar la descripción. En el código fuente real, Runnalbe debe convertirse en consecuencia.
Looper realiza un bucle para hacer algo.
Por ejemplo, en este ejemplo, toma continuamente un elemento de MessageQueue y luego lo pasa a Handler para su procesamiento, y así sucesivamente. Si la cola está vacía, se va a dormir.
Handler es el lugar real para "manejar cosas"
. Utiliza su propio mecanismo de procesamiento para procesar los diversos Objetos entrantes en consecuencia y producir el resultado final.
Para resumirlos en una oración, es:
Looper obtiene continuamente un mensaje en MessageQueue y luego es procesado por Handler.
Realizan sus propias funciones, de forma muy similar a como funciona una CPU en una computadora: la unidad central de procesamiento (Looper)
lee continuamente instrucciones (Mensaje) de la memoria (MessageQueue), ejecuta instrucciones (Manejador) y finalmente produce resultados.
La relación entre Thread y Handler
inserte la descripción de la imagen aquí
① Cada Thread corresponde a solo un Looper;
② Cada Looper corresponde a solo un MessageQueue;
③ Cada MessageQueue tiene N Mensajes;
④ Cada Mensaje especifica como máximo un Handler para manejar eventos.
Se puede inferir de esto que Thread y Handler tienen una relación de uno a muchos.
El papel del Manejador:
1. Manejar Mensaje, que es su trabajo como "manejador".
2. Inserte un mensaje en MessageQueue.
La declaración de función correspondiente para implementar la primera funcionalidad es la siguiente:

public void dispatchMessage(Message msg);//对Message进行分发
public void handleMessage(Message msg);//对Message进行处理


Después de que el Looper tome un Mensaje de MessageQueue, primero llamará a Handler.dispatchMessage para enviar el mensaje, este último distribuirá el Mensaje a la segunda función de la persona responsable correspondiente Handler de acuerdo con la estrategia específica.Se declara la función función correspondiente como sigue:

1Post系列:
final boolean post(Runnable r);
final boolean postAtTime(Runnable r, long uptimeMillis);2Send系列:
final boolean sendEmptyMessage(int what);
final boolean sendMessageAtFrontOfQueue(Message msg);
boolean sendMessageAtTime(Message msg, long uptimeMillis);
final boolean sendMessageDelayed(Message msg, long
delayMillis);等等

El punto común de las dos series de Post y Send es que ambos son responsables de enviar un mensaje a MessageQueue; la diferencia es que el parámetro de función procesado por este último es directamente Message, mientras que Post necesita convertir otros tipos de "dispersos". información en Mensaje primero. y luego llame a la serie de funciones Enviar para ejecutar el siguiente paso.
El "mapa de impresión" que está más cerca de la implementación de Android
inserte la descripción de la imagen aquí
contiene un MessageQueue en Looper. El siguiente es un ejemplo de un hilo común usando Looper, llamado LooperThread:

class LooperThread extends Thread {
    
    
 public Handler mHandler;
 public void run() {
    
    
 Looper.prepare();/*一句简单的prepare,究竟做了些什么工作?
*/
 mHandler = new Handler() {
    
    
 public void handleMessage(Message msg) {
    
    /*处理消息的地方。继承Handler的子类通常需要修改这个函数
*/
 }
 };
 Looper.loop();/*进入主循环*/
 }
 }

Este código es típico en los hilos de Android. En resumen, solo hay 3 pasos
(1) Preparación de Looper (preparar);
(2) Crear un controlador para procesar mensajes;
(3) Looper comienza a operar (bucle).
Analice el código anterior:
primero:

Looper.prepare();

Dado que se van a utilizar las funciones de la clase Looper, se deben realizar las siguientes operaciones en LooperThread:

import android.os.Looper;

Observe cuidadosamente, hay una variable miembro muy importante en Looper:

static final ThreadLocal<Looper> sThreadLocal = new
ThreadLocal<Looper>();

Esta es una variable de tipo estático, lo que significa que una vez importado Looper, sThreadLocal ya existe y está construido. El objeto ThreadLocal es un tipo especial de variable global, porque su naturaleza "global" se limita a su propio subproceso y todos los subprocesos externos (incluso el mismo proceso) no pueden acceder a él. Esto nos dice desde el lado que el Looper de cada hilo es independiente.

preparar:

private static void prepare(boolean quitAllowed) {
    
    
 if (sThreadLocal.get() != null) {
    
    /*sThreadLocal.get返回的
是模板类,这个场景中是Looper。
 这个判断保证一个Thread只会有
一个Looper实例存在*/
 throw new RuntimeException("Only one Looper may be
created per thread");
 }
 sThreadLocal.set(new
Looper(quitAllowed));
 }

sThreadLocal guarda un objeto Looper recién creado.

A continuación, cree un objeto Handler, que extraemos por separado para facilitar la lectura.

public Handler mHandler;
…
mHandler = new Handler() {
    
    
 public void handleMessage(Message msg) {
    
    }
};

Se puede ver que mHandler es una variable miembro de LooperThread y se crea una instancia de Handler a través de la nueva operación.
Handler tiene múltiples constructores, como:

public Handler();
public Handler(Callback callback);
public Handler(Looper looper);
public Handler(Looper looper, Callback callback);

La razón por la que hay tantos constructores es porque Handler tiene las siguientes variables internas que deben inicializarse:

final MessageQueue mQueue;
 final Looper mLooper;
 final Callback mCallback;

Expliquemos su constructor con la primera función utilizada en el ejemplo de LooperThread:

public Handler() {
    
    
 /*…省略部分代码*/
 mLooper =Looper.myLooper();/*还是通过sThreadLocal.get来获取当
前线程中的Looper实例*/
 …
 mQueue= mLooper.mQueue; /*mQueue是Looper与
Handler之间沟通的桥梁*/
 mCallback = null;
}

De esta manera, Handler y Looper, MessageQueue están conectados

Hilo principal de la interfaz de usuario - ActivityThread

public static void main(String[] args) {
    
    Looper.prepareMainLooper();//和前面的LooperThread不同
 ActivityThread thread = new ActivityThread();//新建一个
ActivityThread对象
 thread.attach(false);
 if (sMainThreadHandler == null) {
    
    
 sMainThreadHandler = thread.getHandler();//主Handler
 }
 AsyncTask.init();
 Looper.loop();
 throw new RuntimeException("Main thread loop
unexpectedly exited");
 }

prepareMainLooper y prepare
los hilos ordinarios solo necesitan prepararse, y el hilo principal usa prepareMainLooper.
Los subprocesos ordinarios pueden generar un objeto Handler vinculado a Looper, y el subproceso principal es el controlador obtenido del subproceso actual (thread.getHandler)
(1) prepareMainLooper

public static void prepareMainLooper() {
    
    
 prepare(false);//先调用prepare
 synchronized (Looper.class) {
    
    
 if (sMainLooper != null) {
    
    
 throw new IllegalStateException("The main Looper
has already been prepared.");
 }
 sMainLooper = myLooper();
 }
 }

Como puede ver, prepareMainLooper también necesita usar prepare. El parámetro falso significa que el subproceso no puede salir, lo cual es diferente del anterior LooperThread. Después de la preparación, myLooper puede obtener un objeto Looper de un subproceso local y luego asignarlo a sMainLooper. Desde este punto de vista, el sMainLooper del subproceso principal no es esencialmente diferente de los objetos Looper de otros subprocesos.
inserte la descripción de la imagen aquí
Esta figura describe la situación de Looper de un proceso y sus dos subprocesos internos. El subproceso 1 es el subproceso principal y el subproceso 2 es el subproceso hilo normal hilo. Los cuadros indican el rango al que pueden acceder, por ejemplo, el subproceso 1 no puede acceder directamente al objeto Looper en el subproceso 2, pero ambos pueden acceder a los elementos del proceso.
Subproceso 1: debido a que es el subproceso principal, utiliza prepareMainLooper (). Esta función generará un objeto ThreadLocal Looper para el subproceso 1 a través de prepare (), y permitirá que sMainLooper lo apunte. El propósito de esto es que si otros subprocesos quieren obtener el Looper del subproceso principal, solo necesitan llamar a getMainLooper().
Subproceso 2: como un subproceso ordinario, llama a prepare(); también genera un objeto ThreadLocal Looper, pero solo se puede acceder a este objeto a través de myLooper() en el subproceso. Por supuesto, el hilo principal también puede acceder a su objeto Looper a través de esta función.
(2) sMainThreadHandler.
Cuando se crea el objeto ActivityThread, al mismo tiempo se generará internamente un objeto H heredado de Handler:

final H mH = new H();

El thread.getHandler() llamado en ActivityThread.main devuelve mH.
En otras palabras, ActivityThread proporciona un "administrador de eventos" para manejar varios mensajes en el hilo principal.
Looper.bucle

public static void loop() {
    
    
 final Looper me = myLooper();/*loop函数也是静态的,所以它只能访问静态数据。函数myLooper 则调用sThreadLocal.get()来获取与之匹配的Looper实例(其实 就是取出之前prepare中创建的那个Looper对象)*/final MessageQueue queue = me.mQueue;/*正如我们之前所说,Looper中自带一个MessageQueue*/for (;;) {
    
    //消息循环开始
 Message msg = queue.next();/*从MessageQueue中取出一个消息,可能会阻塞*/
 if (msg == null) {
    
    /*如果当前消息队列中没有msg,说明线程要退出了。类比于上面Windows 伪代码例子中的while判断条件为0,这样就会结束循环*/
 return; /*直接返回,结束程序*/
 }
 …
 msg.target.dispatchMessage(msg); /*终于开始分派消息了,重心就在这里。变量target其实是一个Handler,所以dispatchMessage最终调用的是Handler中的处理函数。*/
 …
 msg.recycle();/*消息处理完毕,进行回收*/
 }
 }

El trabajo principal de la función loop() es extraer continuamente los eventos que deben procesarse de la cola de mensajes y luego distribuirlos a las personas responsables correspondientes. Si la cola de mensajes está vacía, es probable que entre en suspensión para liberar recursos de la CPU. Durante el procesamiento de eventos específicos, el programa publicará nuevos eventos en la cola. Además, otros procesos también pueden publicar nuevos eventos en esta cola. La aplicación APK debe realizar el trabajo de "procesar eventos de la cola" de forma continua hasta que salga, como se muestra en la figura.
inserte la descripción de la imagen aquí
En este diagrama de modelo, después de que el subproceso principal ActivityThread saca el mensaje de la cola de mensajes, llama a su Runnable.run correspondiente para el procesamiento de eventos específicos. En el proceso de procesamiento, es probable que se involucren una serie de llamadas de otras clases (
representadas por Object1 y Object2 en la figura). Y también pueden publicar nuevos eventos en el bucle principal para programar operaciones posteriores. Además, otros procesos también pueden enviar nuevos eventos, como eventos táctiles y eventos clave, al bucle principal de este proceso a través del mecanismo IPC. Esta es la razón fundamental por la que la aplicación APK puede "mover
".
Cola de mensajes

/*以下代码还是Looper.java中的,不过只提取出MessageQueue相关的部分
*/
 final MessageQueue mQueue; /*注意它不是static的*/
 private Looper(boolean quitAllowed) {
    
    
 mQueue = new MessageQueue(quitAllowed); /*new了一个MessageQueue,就是它了。也就是说,当Looper创建时,消息队列也同时会被创建出来*/
 mRun = true;
 mThread = Thread.currentThread();//Looper与当前线程建立对应关系
 }

Los hechos han demostrado que Looper administra un MessageQueue interno, que servirá como almacén de almacenamiento de mensajes de un hilo, y cooperará con Handler y Looper para completar una serie de operaciones.

Clase de hilo

El principio interno de la clase Thread
 public class Thread implementa Runnable { ... Como puede ver, Thread implementa Runnable, lo que significa que los hilos son "código ejecutable":

public interface Runnable {
    
    
 public void run();
}

Runnable es una clase de interfaz abstracta, el único método proporcionado es run(). En general, usamos Thread como este:
Método 1, heredar de Thread
Defina un MyThread heredado de Thread, reescriba su método de ejecución y luego llame:

MyThread thr = new MyThread();
thr.start();

Método 2,
la clave para implementar directamente Runnable Thread es Runnable, por lo que el siguiente es otro uso común:

new Thread(Runnable target).start();

Ambos métodos se inician en última instancia con start, que llama indirectamente a la implementación de ejecución anterior.

 checkNotStarted();
 hasBeenStarted = true;
 VMThread.create(this, stackSize);/*这里是真正创
建一个CPU线程的地方*/
}

Antes de esto, hemos estado ejecutando en el "hilo anterior" hasta VMThread.create, pero de hecho, solo el método Run se está ejecutando en el nuevo hilo, lo que explica que el segundo método anterior también puede pasar en un Runnable. La razón por la que funciona . Desde esta perspectiva, la clase Thread solo puede considerarse como un intermediario.La tarea es iniciar un hilo para ejecutar el Runnable especificado por el usuario, independientemente de si el Runnable pertenece a sí mismo, como se muestra en la Figura 5-13.
inserte la descripción de la imagen aquí
El subproceso tiene los siguientes estados:
public enum State { NEW, //El subproceso se ha creado, pero aún no se ha iniciado RUNNABLE, //En el estado ejecutable, todo está listo BLOCKED, //En el estado bloqueado, como esperando para que se libere un bloqueo ESPERA , //en estado de espera TIMED_WAITING, //espera por un tiempo específico TERMINATED //finaliza la ejecución }






Hilo dormir y despertar

1. Las tres funciones esperar y notificar/notificar a todos
están definidas por la clase de objeto, lo que significa que son "propiedades" comunes de cualquier clase.
inserte la descripción de la imagen aquí
Cuando un subproceso (como el subproceso donde se encuentra SystemServer) llama al método de espera de un objeto (como como BlockingRunnable), el sistema registrará la solicitud en este objeto. Debido a que puede haber más de una persona que llama, puede usar
la forma de una lista (vea la lista de espera en la Figura 5-15) para agregarlos uno por uno. Cuando se cumple la condición de activación tardía (es decir, después de que se ejecuta BlockingRunnable), el objeto puede usar notificar para activar un subproceso en espera en la lista, o usar notificar a todos para activar todos los subprocesos en la lista, como se muestra en la figura 5
. -15
inserte la descripción de la imagen aquí
2.interrupt
El propósito de llamar a la interrupción de un hilo es el mismo que el significado literal de la palabra, que es "interrumpir" su proceso de ejecución. En este punto, existen las siguientes tres posibilidades.
1. Si el subproceso se bloquea en espera de un objeto, o en el método join(), sleep(), se activará, se borrará el estado de interrupción y se recibirá una excepción interrumpida.
2. Si el subproceso está bloqueado en la operación de E/S de InterruptibleChannel, se establecerá el estado de interrupción y se recibirá una excepción ClosedByInterruptException y el canal se cerrará en este momento.
3. Si el Thread está bloqueado en el Selector, el estado de interrupción se establecerá y regresará inmediatamente sin recibir ninguna excepción.
3. join
El método join tiene los siguientes prototipos:

public final void join ();
public final void join (long millis, int nanos);
public final void join (long millis);

Por ejemplo:

Thread t1 = new Thread(new ThreadA()); 
Thread t2 = new Thread(new ThreadB()); 
t1.start(); 
t1.join(); 
t2.start();

Lo que espera lograr es que solo cuando se complete la ejecución del hilo t1, continuaremos ejecutando el siguiente t2.start(). Esto asegura la ejecución secuencial de los dos hilos. El join() con un parámetro de tiempo tiene una restricción adicional, es decir, si t1 no se ejecuta dentro del tiempo especificado, continuaremos ejecutando las siguientes declaraciones para evitar que la "espera infinita" arrastre todo el programa.
4. La espera de suspensión
es para esperar un objeto, mientras que la suspensión es el tiempo de espera, una vez que finaliza el tiempo establecido, se despertará.

Migración de estado de hilo
inserte la descripción de la imagen aquí
Instancia combinada Thread+Handler+Looper
BusinessThread

private Thread mBusinessThread = null;
private boolean mBusinessThreadStarted = false;
private BusinessThreadHandler mBusinessThreadHandler = null; 
private void startBusinessThread()
{
    
    
 if (true == mBusinessThreadStarted)
 return;
 else
 mBusinessThreadStarted = true;
 mBusinessThread = new Thread(new Runnable()
 {
    
    
 @Override
 public void run()
 {
    
    
 Looper.prepare();
 mBusinessThreadHandler = new
BusinessThreadHandler();
 Looper.loop();
 }
 });
 mBusinessThread.start();
}

BusinessThread reescribe el método de ejecución y usa Looper.prepare y Looper.loop para procesar continuamente las solicitudes de ajuste. Estas solicitudes se envían a la cola de mensajes de BusinessThread a través de mBusinessThreadHandler.

public class BusinessThreadHandler extendsHandler
{
    
    
 public boolean sendMessage(int what, int arg1, int arg2)//重写sendMessage
 {
    
    
 removeMessages(what); //清理消息队列中未处理的请求
 return super.sendMessage(obtainMessage(what, arg1,arg2));//发送消息到队列
 }
 public void handleMessage(Message msg)
 {
    
    
 switch(msg.what)
 {
    
    
 case MSG_CODE:
 //在这里执行耗时操作
 break;
 default:
 break;
 }
 }
};

Cómo las aplicaciones de Android aprovechan las capacidades de procesamiento multinúcleo de la CPU

¿Cómo pueden los desarrolladores tomar la iniciativa de usar las capacidades multinúcleo de la CPU para mejorar efectivamente el rendimiento de sus propias aplicaciones?
La respuesta es la tecnología de programación paralela basada en Java.
La primera forma es el hilo de Java, que también es aplicable en el sistema Android. No hay mucha diferencia en el uso de Java, solo necesitamos heredar la clase Thread o implementar la interfaz Runnable. Sin embargo, es un poco problemático usar este método, es decir, la comunicación con el subproceso principal debe pasar a través de Message Queue, porque solo el subproceso principal puede manejar asuntos relacionados con la interfaz de usuario, incluida la actualización de la interfaz de interfaz de usuario. Otro método de programación paralelo opcional es
AsyncTask , que es una clase de tipo Helper especialmente desarrollada por Android para simplificar la implementación de subprocesos múltiples. La ventaja es obvia, es decir, no necesita comunicarse con el subproceso de la interfaz de usuario a través de los engorrosos Looper, Handler y otros mecanismos.
AsyncTask está diseñado para operaciones en segundo plano relativamente a corto plazo. En otras palabras, si necesita realizar ciertas transacciones en segundo plano durante mucho tiempo, le recomendamos que use Executor, ThreadPoolExecutor y FutureTask y otras interfaces API.
El tercer modelo de implementación de "subproceso de trabajo" más utilizado es IntentService.

Flujo de inicio típico para una aplicación de Android

Las aplicaciones tipo APK, por lo general, se inician en el sistema de dos maneras:
1. Haga clic en el icono de la aplicación correspondiente en el Iniciador para iniciar.
Esta forma de inicio la inicia principalmente el usuario. De forma predeterminada, la aplicación APK tendrá un icono en la interfaz principal del Lanzador y se puede iniciar una Actividad especificada por la aplicación haciendo clic en ella.
2. Iniciar por startActivity
Este método de inicio normalmente existe dentro del código fuente. Por ejemplo, inicie Activity2 a través de startActivity en Activity1.
Los procesos de estos dos métodos de inicio son básicamente los mismos y eventualmente llamarán a startActivity de ActivityManagerService para completar.

inserte la descripción de la imagen aquí
No importa qué método se use para iniciar el proceso de inicio de una actividad, eventualmente llamará a la función startActivity de AMS.

Si todo va bien, AMS finalmente intentará iniciar la actividad especificada. Si el lector ha escrito una aplicación APK, debe quedar claro que además de onCreate, onResume, existen onPause, onStop, etc. en el ciclo de vida de la Actividad. Entre ellos, onPause se
llama en este momento, porque el sistema Android estipula que antes de que comience la nueva Actividad, la Actividad que estaba originalmente en el estado reanudado se pausará. Este método de administración es mucho más simple que el sistema de ventanas múltiples de Windows y puede satisfacer completamente las necesidades generales de los dispositivos móviles. La configuración de una
actividad para pausar se realiza principalmente a través del método ApplicationThread.schedulePauseActivity del proceso al que pertenece la actividad. ApplicationThread es un canal Binder proporcionado por el proceso de solicitud a AMS.

Después de recibir la solicitud de pausa, el subproceso principal de ActivityThread de este proceso seguirá procesando. Además de los métodos familiares, como llamar a Activity.onPause(), también debe notificar a WindowManagerService de este cambio, porque la interfaz de usuario también debe cambiar. Después de hacer esto, el proceso notifica a AMS que su solicitud de pausa ha sido ejecutada, para que AMS pueda continuar completando la operación startActivity anterior.

Si el proceso al que pertenece la actividad que se va a iniciar no existe, entonces AMS debe iniciarlo primero. Este paso lo implementa Process.start, cuyo primer parámetro de entrada es "android.app.ActivityThread", que es el hilo principal de la aplicación, y luego llama a su función principal.

Después de que ActivityThread comience y complete el trabajo de inicialización correspondiente, debe llamar a addedApplication para notificar a AMS, de modo que este último pueda continuar ejecutando el proceso startActivity inconcluso. Específicamente, AMS solicita a la aplicación que inicie una actividad específica a través de ApplicationThread.scheduleLaunchActivity. La serie de trabajo subsiguiente debe ser realizada por el propio proceso de la aplicación, como crear
Ventana por actividad, ViewRootImpl, atravesar View Tree, etc.

Supongo que te gusta

Origin blog.csdn.net/jifashihan/article/details/129280398
Recomendado
Clasificación