Introducción a Aidl ----- Razones y soluciones habituales para pisar fosos

Tabla de contenido

0. Prefacio

1. Introducción a la estructura de directorios

2. Introducción a la interfaz y función de cada botón

3. Introducción a la lógica de ejecución de cada código de botón

4. Análisis de código

5. Pisar fosas y soluciones

6. Demostración del proyecto


0. Prefacio

Recientemente, AIDL se ha utilizado en desarrollo. He leído muchos artículos en esta área en Internet. Todos son muy buenos, pero cuando lo reproduzca, encontraré varios problemas, por lo que decidí escribir un artículo en esta área y proporcione algunos artículos fáciles de seguir. Las razones y las soluciones para los pits son limitadas. Si hay errores de análisis, espero que todos puedan proponerlos activamente. (Nota: la fuente roja es un punto de conocimiento más importante)

1. Introducción a la estructura de directorios

Primero, introduzca la estructura de directorios de este artículo (si desea saber más sobre la función de cada directorio común en Android Studio, consulte ( marcador de posición, se espera que se complete para 2020.08) ). La estructura de directorios ya ha incluido todos los archivos importantes involucrados en este artículo. Se enumeran, y la función de estos archivos en el artículo se explicará claramente más adelante. El proyecto AidlDemo contiene dos submódulos: cliente y aidlservice. La parte principal del cliente es MainActivity y GeneralService. La función de este módulo es mostrar cómo MainActivity inicia y finaliza GeneralService, y cómo vincular y desvincular GeneralService. Además de llamar al servicio de su propio módulo, MainAcivity también puede vincular y desvincular el AidlService en el aidlservice a través de la interfaz AIDL. Cabe señalar que MainActivity en el módulo aidlservice de este artículo no es el núcleo y puede eliminarse.

AidlDemo
   |--client
   |     |--build
   |     |     |--generated
   |     |     |      |--aidl_source_output_dir
   |     |     |                  |--debug
   |     |     |                       |--compileDebugAidl
   |     |     |                                  |--out
   |     |     |--outputs                             |--aidl
   |     |          |--apk                                 |--IAidlService.java-------(1)
   |     |              |--debug               
   |     |                   |--client-debug.apk--------------------------------------(2)                                      
   |     |--src
   |     |   |--main
   |     |        |--aidl
   |     |        |   |--IAidlService.aidl--------------------------------------------(3)
   |     |        |--java
   |     |        |    |--com.zhouxi.client
   |     |        |            |--GeneralService.java---------------------------------(4)
   |     |        |            |--MainActivity.java-----------------------------------(5)
   |     |        |--res
   |     |        |   |--layout
   |     |        |         |--activity_main.xml--------------------------------------(6)
   |     |        |--AndroidManifest.xml----------------------------------------------(7)
   |     |--build.gradle--------------------------------------------------------------(8)
   |     
   |--aidlservice
   |     |--build
   |     |     |--generated
   |     |     |     |--aidl_source_output_dir
   |     |     |                  |--debug
   |     |     |                       |--compileDebugAidl
   |     |     |                                |--out
   |     |     |--outputs                           |--aidl
   |     |           |--apk                              |--IAidlService.java---------(9)
   |     |               |--debug
   |     |                    |--aidlservice-debug.apk-------------------------------(10)
   |     |--src
   |     |   |--main
   |     |        |--aidl
   |     |        |   |--IAidlService.aidl-------------------------------------------(11)
   |     |        |--java
   |     |        |   |--com.zhouxi.service
   |     |        |             |--AidlService.java----------------------------------(12)
   |     |        |             |--MainActivity.java---------------------------------(13)
   |     |        |--res
   |     |        |   |--layout
   |     |        |         |--activity_main.xml-------------------------------------(14)
   |     |        |--AndroidManifest.xml---------------------------------------------(15)
   |     |--build.gradle-------------------------------------------------------------(16)
   |
   |--build.gradle-------------------------------------------------------------------(17)
   |--setting.gradle-----------------------------------------------------------------(18)
                                        
                                        AidlDemo目录结构

2. Introducción a la interfaz y función de cada botón

La primera imagen simula el cliente cliente, que contiene seis botones: INICIAR SERVICIO, DETENER SERVICIO, VINCULAR SERVICIO, DESVINCULAR SERVICIO, VINCULAR SERVICIO AIDL y DESVincular SERVICIO AIDL.

  • Los dos primeros botones proporcionan el inicio y el apagado de GeneralService en el mismo módulo, y no existe una relación vinculante entre los dos.
  • Los dos botones del medio proporcionan la función de vincular y desvincular GeneralService en el mismo módulo.
  • Los siguientes dos botones proporcionan la función de MainActivity en el cliente para vincular y desvincular AidlService en aidlservice usando la interfaz AIDL.

(Nota: La actividad principal de aidlservice no es necesaria. AidlService se puede utilizar solo como un servicio en segundo plano. Por lo tanto, el servicio aidl que se muestra a la derecha no requiere una interfaz. Los dos botones están especialmente diseñados para depurar)

Serviciocliente

3. Introducción a la lógica de ejecución de cada código de botón

3.1 INICIAR SERVICIO 和 DETENER SERVICIO 

Este método de inicio del servicio es solo para iniciar GeneralService, pero no existe una relación vinculante entre los dos. Es decir, cuando MainActivity ya no se está ejecutando, GeneralService no se cerrará . Por supuesto, MainActivity puede proporcionar la función de cerrar manualmente el GeneralService.

  • START SERVICE solo necesita poner el nombre de la clase actual y el nombre de la clase para saltar al intent, y ejecutar directamente startService (intent) para iniciar GeneralService.
Intent intent = new Intent(this, GeneralService.class);
startService(intent);
  • STOP SERVICE es similar a iniciar el servicio, simplemente cambie startService a stopService.
Intent intent = new Intent(this, GeneralService.class);
stopService(intent);

3.2 SERVICIO DE VINCULACIÓN 和 SERVICIO DE DESVinculación

A diferencia de la simple apertura y cierre del servicio anterior, este método de iniciar el servicio vincula el ciclo de servicio de GeneralService a MainActivity. Una vez que MainActivity está cerrada, GeneralService también se cerrará (nota: por el contrario, cuando GeneralService está cerrado, MainAcitivy no se cerrará) . Específicamente:

  • BIND SERVICE El servicio de vinculación requiere bindService, que requiere tres parámetros: Intent, ServiceConnection y flag. Entre ellos, Intent registra principalmente la información transmitida entre MainActivity y GeneralService. Dado que ambos pertenecen al mismo módulo, es decir, en el mismo apk, solo necesita pasar el nombre de clase de ambos (tenga en cuenta esto y use la interfaz AIDL para cruzar la diferencia entre las llamadas apk).
Intent intent = new Intent(this, GeneralService.class);
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
  • La función de ServiceConnection es supervisar el estado de vinculación de los dos y recibir el objeto IBinder pasado de GeneralService. ServiceConnection implementa onServiceConnected y onServiceDisconnected. Después de que onServiceConnected se vincule correctamente, devolverá un objeto IBinder.
public ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e(TAG, "onServiceConnected: bind GeneralService success.");
            GeneralService.GeneralBinder generalBind = (GeneralService.GeneralBinder) service;
            generalBind.readWriteInfo();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e(TAG, "onServiceDisconnected: bind GeneralService fail.");
        }
    };
  • Y este objeto es una clase interna de GeneralService.
class GeneralBinder extends Binder {
    public void readWriteInfo() {
        String info = readServiceInfo();
        Log.e(TAG, "getInfo: readServiceInfo success, the information: " + info);
        writeServiceInfo("This is writeServiceInfo in GeneralBinder.");
        Log.e(TAG, "getInfo: writeServiceInfo success.");
    }
}
  • ¿Por qué necesitamos definir una clase interna? Debido a que en general MainActivity no puede acceder directamente a los métodos en GeneralService, una clase interna se define a través de GeneralService. La clase interna puede definir algunos métodos. Estos métodos llaman a los métodos a los que accede GeneralService, y MainActivity implementa indirectamente los métodos para acceder a GeneralService.
  • UNBIND SERVICE necesita usar unbindService para desvincular. El parámetro de entrada es solo ServiceConnection. Cabe señalar que solo los métodos onUnbind y onDestroy en GeneralService se ejecutarán al desvincular. Este método no se ejecuta cuando se vincula .
unbindService(aidlServiceConnection);

3.3 SERVICIO BIND AIDL 和 SERVICIO DESVINCULAR AIDL 

Este método de enlace es similar al método de enlace anterior, la diferencia es que MainActivity y GeneralService anteriores están en el mismo módulo, es decir, el mismo apk, MainActivity puede encontrar fácilmente GeneralService ingresando directamente el nombre de la clase al iniciar la posición de GeneralService . Cuando MainActivity y AidlService están en diferentes apk, es decir, si un apk quiere acceder a las funciones del servicio en otro apk, necesita usar la interfaz AIDL para proporcionar un puente intermedio para realizar la llamada de función entre el apk. (Nota: El apk no necesariamente tiene una interfaz. Un solo AidlService también se puede empaquetar en un apk como un servicio en segundo plano. Esto está relacionado con el directorio donde está instalado el apk, como el directorio del sistema. El apk en este directorio no se puede ver en el escritorio móvil. Servicios del sistema visibles, pero se requieren permisos de root durante el proceso de instalación. Los directorios normales generalmente tienen una interfaz y el software correspondiente se puede ver en el teléfono)

  • BIND AIDL SERVICE es similar a BIND SERVICE, ambos llaman a bindService (Intent, ServiceConnection, flag), la diferencia radica en Intent y ServiceConnection. Para Intent, dado que el servicio vinculado por BIND SERVICE pertenece al mismo APK que él mismo, es fácil encontrar el servicio correspondiente a través del nombre de la clase. El servicio vinculado por BIND AIDL SERVICE pertenece a un APK diferente a sí mismo, durante el proceso de vinculación es necesario encontrar el servicio vinculado a través del nombre del paquete y la ACCIÓN correspondiente.
Intent intent = new Intent();
intent.setAction("com.zhouxi.service.AidlService");
intent.setPackage("com.zhouxi.service");
bindService(intent, aidlServiceConnection, Context.BIND_AUTO_CREATE);
  • Para ServiceConnection, los dos usan la misma clase, pero los objetos IBinder devueltos son diferentes (nota: se necesitan diferentes tipos de variables para recibir) ,
public ServiceConnection aidlServiceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        Log.e(TAG, "onServiceConnected: bind AidlService success.");
        IAidlService aidlService = IAidlService.Stub.asInterface(service);
        try {
            Log.e(TAG, "onServiceConnected: the info of AidlService: " + aidlService.getServiceInfo());
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        Log.e(TAG, "onServiceConnected: bind AidlService fail.");
    }
};
  • GeneralService define internamente una clase interna heredada de IBinder y devuelve este tipo de objeto a onServiceConnected a través de onBinder. AidlService también proporciona la función de servicio de llamada al personalizar la clase interna, pero la clase interna hereda de IAIdlService.Stub, nada más, esencialmente definen la clase interna y pasan el objeto de la clase interna al cliente, para lograr el propósito del cliente para llamar al servicio.
//两个内部类对比
class GeneralBinder extends Binder {
    public void readWriteInfo() {
        String info = readServiceInfo();
        Log.e(TAG, "getInfo: readServiceInfo success, the information: " + info);
        writeServiceInfo("This is writeServiceInfo in GeneralBinder.");
        Log.e(TAG, "getInfo: writeServiceInfo success.");
    }
}
================================================================================
class AidlBinder extends IAidlService.Stub {
    @Override
    public String getServiceInfo() {
        Log.e(TAG, "getServiceInfo: This is getServiceInfo in AidlBinder.");
        return info;
    }
}
  • Al observar los parámetros de entrada de onServiceConnected, puede encontrar que independientemente de si se usa el método AIDL, el segundo parámetro es del tipo IBinder. Aunque no conocemos la relación entre la clase padre Binder y IAIdlService.Stub heredada por las dos clases internas, una cosa es segura es que ambas son tipos IBinder . A través de esta comparación, la diferencia entre los dos es muy clara. Entonces, ¿qué es IAdlService? ¿Qué es IAidlService.Stub y cuál es la diferencia entre los dos? Para un análisis específico, consulte este artículo (marcador de posición: se espera que se complete el 21.7.2020). Volviendo a la comparación de las dos clases internas, la clase interna de GeneralService define directamente un Método, a través de este método para obtener la función proporcionada por GeneralService, la clase interna de AidlService obtiene la función proporcionada por el servicio implementando el método de la interfaz IAIdlService.
  • Unbind UNBIND AIDL SERVICE es el mismo que el de GeneralService, así que no lo presentaré más.
unbindService(aidlServiceConnection);

4. Análisis de código

Esta es la MainActivity del módulo cliente, que es la interfaz de los seis botones en la figura anterior. Esta clase define seis botones para permitir abrir y cerrar GeneralService, vincular y desvincular GeneralService, y vincular y desvincular AidlService en otro apk.

Se definen dos ServiceConnected: serviceConnected y aidlServiceConnected se utilizan para detectar si la vinculación es exitosa, y si la vinculación es exitosa, recibirán el objeto IBinder devuelto por el servicio respectivamente.

package com.zhouxi.client;

import aidl.IAidlService;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    public static final String TAG = MainActivity.class.getSimpleName();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.startGeneralService).setOnClickListener(this);
        findViewById(R.id.stopGeneralService).setOnClickListener(this);
        findViewById(R.id.bindGeneralService).setOnClickListener(this);
        findViewById(R.id.unbindGeneralService).setOnClickListener(this);
        findViewById(R.id.bindAidlService).setOnClickListener(this);
        findViewById(R.id.unbindAidlService).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.startGeneralService) {
            Intent intent = new Intent(this, GeneralService.class);
            startService(intent);
        } else if (v.getId() == R.id.stopGeneralService) {
            Intent intent = new Intent(this, GeneralService.class);
            stopService(intent);
        } else if (v.getId() == R.id.bindGeneralService) {
            Intent intent = new Intent(this, GeneralService.class);
            bindService(intent, serviceConnection, BIND_AUTO_CREATE);
        } else if (v.getId() == R.id.unbindGeneralService) {
            unbindService(serviceConnection);
        } else if (v.getId() == R.id.bindAidlService) {
            Intent intent = new Intent();
            intent.setAction("com.zhouxi.service.AidlService");
            intent.setPackage("com.zhouxi.service");
            bindService(intent, aidlServiceConnection, Context.BIND_AUTO_CREATE);
        } else if (v.getId() == R.id.unbindAidlService) {
            Log.e(TAG, "onClick: unbindAidlService");
            unbindService(aidlServiceConnection);
        }
    }

    public ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e(TAG, "onServiceConnected: bind GeneralService success.");
            GeneralService.GeneralBinder generalBind = (GeneralService.GeneralBinder) service;
            generalBind.readWriteInfo();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e(TAG, "onServiceDisconnected: bind GeneralService fail.");
        }
    };

    public ServiceConnection aidlServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e(TAG, "onServiceConnected: bind AidlService success.");
            IAidlService aidlService = IAidlService.Stub.asInterface(service);
            try {
                Log.e(TAG, "onServiceConnected: the info of AidlService: " + aidlService.getServiceInfo());
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e(TAG, "onServiceConnected: bind AidlService fail.");
        }
    };
}

 GeneralService hereda de Service e implementa los métodos de servicio onBind y onUnbind. Cuando MainActivity llama para iniciar el servicio, el método onBind se ejecuta para devolver una instancia de la clase interna. Esta clase interna define algunos métodos para llamar a los métodos internos de GeneralService, permitir indirectamente que MainActivity llame al método de GeneralService. Cuando MainActivity no esté vinculado, ejecute el método onUnbind.

package com.zhouxi.client;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.Nullable;

public class GeneralService extends Service {
    private static final String TAG = GeneralService.class.getSimpleName();

    private String info = "This is GeneralService info.";

    @Override
    public void onCreate() {
        Log.e(TAG, "onCreate: GeneralService is onCreate.");
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(TAG, "onStartCommand: GeneralService is onStartCommand.");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        Log.e(TAG, "onDestroy: GeneralService is onDestroy.");
        super.onDestroy();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.e(TAG, "onBind: GeneralService is onBind.");
        return new GeneralBinder();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.e(TAG, "onUnbind: GeneralService is onUnbind.");
        return super.onUnbind(intent);
    }

    class GeneralBinder extends Binder {
        public void readWriteInfo() {
            String info = readServiceInfo();
            Log.e(TAG, "getInfo: readServiceInfo success, the information: " + info);
            writeServiceInfo("This is writeServiceInfo in GeneralBinder.");
            Log.e(TAG, "getInfo: writeServiceInfo success.");
        }
    }

    public String readServiceInfo() {
        Log.e(TAG, "readServiceInfo: this is readServiceInfo in GeneralService.");
        return info;
    }

    public void writeServiceInfo(String info) {
        Log.e(TAG, "writeServiceInfo: this is writeServiceInfo in GeneralService.");
        this.info = info;
    }
}

Este es el archivo AndroidManifest del módulo cliente. Se centra principalmente en el nombre del paquete package = "com.zhouxi.client" y la información de registro de los dos componentes (puede revisar los cuatro componentes en Android que no conoce) . ¿Cuál es el uso de esta información de registro? En términos generales, si es necesario utilizar los cuatro componentes principales, deben registrarse (declararse) en el AndroidManifest; de lo contrario, cuando sea necesario llamar al componente durante la ejecución del apk, el sistema irá al archivo xml para encontrar el apk que es Si no hay tal nombre de componente, se bloqueará directamente si no lo es. Esta es también una causa de bloqueo común en la depuración de apk de Android.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.zhouxi.client">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        //MainActivity注册信息
        <activity android:name="com.zhouxi.client.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        //GeneralService注册信息
        <service android:name="com.zhouxi.client.GeneralService"/>
    </application>

</manifest>

La interfaz IAidlService es el puente de comunicación entre MainActivity y AidlService. La interfaz define el método getServiceInfo. AidlService define una clase interna AidlBinder heredada de IAIdlService.Stub, que se analizó anteriormente. Al observar los parámetros de entrada del onServiceConnected de aidlServiceConnected, puede determinar el IAIdlService. Stub es un objeto de tipo IBinder. Continúe estudiando la siguiente sección (marcador de posición: se espera que se complete el 20 de julio de 2020) . Aquí podemos imaginar esta clase interna de AidlBinder como GeneralBinder en otro servicio, y su pasos De hecho, es casi lo mismo, pero la clase interna de AidlBinder hereda la interfaz IAIdlService, por lo que necesita implementar el método definido por la interfaz. Entonces MainActivity accede indirectamente a las funciones de AidlService a través de los métodos definidos por esta clase interna.

// IAidlService.aidl
package aidl;

interface IAidlService {
    String getServiceInfo();
}
package com.zhouxi.service;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

import aidl.IAidlService;
import androidx.annotation.Nullable;

public class AidlService extends Service {
    private static final String TAG = AidlService.class.getSimpleName();

    private String info = "This is AidlService info.";

    @Override
    public void onCreate() {
        Log.e(TAG, "onCreate: AidlService is onCreate.");
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(TAG, "onStartCommand: AidlService is onStartCommand.");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        Log.e(TAG, "onDestroy: AidlService is onDestroy.");
        super.onDestroy();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.e(TAG, "onBind: AidlService is onBind.");
        return new AidlBinder();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.e(TAG, "onUnbind: AidlService is onUnbind.");
        return super.onUnbind(intent);
    }

    class AidlBinder extends IAidlService.Stub {
        @Override
        public String getServiceInfo() {
            Log.e(TAG, "getServiceInfo: This is getServiceInfo in AidlBinder.");
            return info;
        }
    }
}

Este es el archivo AndroidManifest del módulo aidlservice. Ya lo presenté anteriormente. Aquí solo presentaré la función de filtro de intención. Verifique el proceso de MainActivity iniciando AidlService: Action y Package se pasan en el Intent. La función de la La intención es principalmente transmitir información. Aquí está para decirle al sistema cuando bindService cuál es el nombre del paquete del servicio que voy a vincular ahora, por qué no puedo escribir el nombre de la clase directamente como el anterior, porque estos son dos apks, que debe ser operado por un intermediario La función de la acción definida al mismo tiempo puede entenderse como el "signo secreto" llamado entre los dos apks. Has definido esta característica en AndroidManifest. También inyecto este "signo secreto" cuando busco el servicio, ¿te puedo encontrar?

Intent intent = new Intent();
intent.setAction("com.zhouxi.service.AidlService");
intent.setPackage("com.zhouxi.service");
bindService(intent, aidlServiceConnection, Context.BIND_AUTO_CREATE);
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.zhouxi.service">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service
            android:name=".AidlService">
            <intent-filter>
                <action android:name="com.zhouxi.service.AidlService"/>
            </intent-filter>
        </service>
    </application>

</manifest>

 Sin mencionar el archivo main_activity, define seis botones para mostrar en la página de inicio y proporcionar una función de respuesta al clic.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.zhouxi.client.MainActivity">

    <Button
        android:id="@+id/startGeneralService"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start service"/>

    <Button
        android:id="@+id/stopGeneralService"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Stop service"/>

    <Button
        android:id="@+id/bindGeneralService"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Bind service"/>

    <Button
        android:id="@+id/unbindGeneralService"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="unbind service"/>

    <Button
        android:id="@+id/bindAidlService"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Bind aidl service"/>

    <Button
        android:id="@+id/unbindAidlService"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Unbind aidl service"/>

</LinearLayout>

5. Pisar fosas y soluciones

Antes de realizar la prueba, solucionemos algunos de los pozos fáciles en la demostración de este artículo. Este es también el lugar más importante de este artículo. Puede resolver muchos pozos que encuentre.

1. ¿Por qué se bloquea mi apk durante el funcionamiento?

Solución 1: Preste atención al archivo AndroidManifest para ver si el componente correspondiente se ha registrado en el archivo. Si el componente correspondiente no está registrado y resulta que se llama al componente, se producirá un bloqueo.

Solución 2: si hay una excepción en el código, habrá un bloqueo, por lo que en la codificación normal, debe desarrollar un buen hábito de impresión de registros, intente utilizar el registro para localizar el problema, cómo utilizar el registro para localizar el problema de manera eficiente, consulte este artículo Artículo (marcador de posición: se espera que se complete para 2020.08) ?

2. ¿Por qué la clase interna en el servicio muestra que no se puede encontrar la interfaz al implementar la interfaz?

Para que la interfaz AIDL en ambos lados del cliente y el servidor proporcione sus propias llamadas de clase y para lograr la comunicación entre los dos apks, se deben cumplir las siguientes condiciones:

  1. Consulte (3) de la estructura del directorio superior AidlDemo, el paquete aidl debe existir y el paquete aidl debe estar al mismo nivel que java. El archivo IAIdlService.aidl debe guardarse en aidl, se puede guardar directamente en aidl, o se puede crear un nuevo paquete en aidl save.
  2. El nombre del paquete debe corresponder al nombre del paquete superior en la clase IAIdlService.aidl.
  3. Debe compilarse con anticipación y el resultado compilado se guardará en (1). Sin este archivo, el IAIdlService no se puede importar y se informará un error de compilación.
  4. El nombre del paquete de IAIdlService en el cliente y el servidor debe ser el mismo. Cabe señalar que si no se cumplen las tres primeras condiciones, la compilación fallará. Si los tres primeros elementos están todos satisfechos y el cuarto elemento no está satisfecho, el programa puede ejecutarse normalmente, pero se bloqueará cuando se llame a través de apk.

Si desea saber más sobre la ubicación de almacenamiento de la interfaz AIDL, consulte este artículo (ocupado, se espera que se complete el 2020.07.20) .

6. Demostración del proyecto

A continuación, verifiquemos los siguientes efectos. Haga clic en los seis botones uno por uno, y el registro impreso es el siguiente. A través del registro, podemos encontrar la relación de llamada de cada función:

INICIAR SERVICIO: Después de iniciar el servicio, llame directamente al onCreate-> onStartCommand del servicio GeneralService

DETENER SERVICIO: Cerrar el servicio y llamar directamente Destrucción del servicio GeneralService

BIND SERVICE: Después de vincular el servicio, el servicio primero abre el onCreate del servicio AidlService -> llama al método onBind del servicio y devuelve el objeto IBinder -> el método onServiceConnected recibe el objeto devuelto por el servicio -> la función principal llama al método de el objeto para acceder al método interno de GeneralService.

DESVINCULAR SERVICIO: Después de desvincular el servicio, GeneralService llama a onBind-> onDestroy.

BIND AIDL SERVICE y UNBIND AIDL SERVICE son similares al proceso de vinculación mencionado anteriormente y no se presentarán en detalle.

El siguiente es el registro de los seis botones en los que se hace clic sucesivamente Es más fácil comprender el proceso de llamada de la función a través del registro y el código anterior.

//START SERVICE
2020-07-15 00:34:47.208 13981-13981/com.zhouxi.client E/GeneralService: onCreate: GeneralService is onCreate.
2020-07-15 00:34:47.209 13981-13981/com.zhouxi.client E/GeneralService: onStartCommand: GeneralService is onStartCommand.

//STOP SERVICE
2020-07-15 00:34:50.445 13981-13981/com.zhouxi.client E/GeneralService: onDestroy: GeneralService is onDestroy.

//BIND SERVICE
2020-07-15 00:34:51.578 13981-13981/com.zhouxi.client E/GeneralService: onCreate: GeneralService is onCreate.
2020-07-15 00:34:51.578 13981-13981/com.zhouxi.client E/GeneralService: onBind: GeneralService is onBind.
2020-07-15 00:34:51.580 13981-13981/com.zhouxi.client E/MainActivity: onServiceConnected: bind GeneralService success.
2020-07-15 00:34:51.580 13981-13981/com.zhouxi.client E/GeneralService: readServiceInfo: this is readServiceInfo in GeneralService.
2020-07-15 00:34:51.580 13981-13981/com.zhouxi.client E/GeneralService: getInfo: readServiceInfo success, the information: This is GeneralService info.
2020-07-15 00:34:51.580 13981-13981/com.zhouxi.client E/GeneralService: writeServiceInfo: this is writeServiceInfo in GeneralService.
2020-07-15 00:34:51.580 13981-13981/com.zhouxi.client E/GeneralService: getInfo: writeServiceInfo success.

//UNBIND SERVICE
2020-07-15 00:34:52.321 13981-13981/com.zhouxi.client E/GeneralService: onUnbind: GeneralService is onUnbind.
2020-07-15 00:34:52.321 13981-13981/com.zhouxi.client E/GeneralService: onDestroy: 
GeneralService is onDestroy.

//BIIND AIDL SERVICE
2020-07-15 00:34:53.044 13981-13981/com.zhouxi.client E/MainActivity: onServiceConnected: bind AidlService success.
2020-07-15 00:34:53.046 13981-13981/com.zhouxi.client E/MainActivity: onServiceConnected: the info of AidlService: This is AidlService info.

//UNBIND AIDL SERVICE
2020-07-15 00:34:53.683 13981-13981/com.zhouxi.client E/MainActivity: onClick: unbindAidlService

 

 

 

Supongo que te gusta

Origin blog.csdn.net/weixin_48968045/article/details/107216295
Recomendado
Clasificación