English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Análisis detallado de la comunicación IPC entre procesos en Android: operaciones AIDL en el último AndroidStudio

Introducción

Anteriormente, se organizó la comunicación entre hilos en Android 《¿Cuál es la relación entre Thread、Handler y HandlerThread?》 , estos están en el mismo proceso, ¿cómo se realiza la comunicación entre procesos, o la comunicación entre diferentes aplicaciones? En este momento, se debe usar AIDL (Android Interface Definition Language, Lenguaje de Definición de Interfaz de Android).

Método de uso (AndroidStudio)

He encontrado que los tutoriales sobre AIDL básicamente son de Eclipse, pero al usar AIDL en AndroidStudio hay algunas diferencias, veamos cómo hacerlo, primero creamos un proyecto como el servidor:

Después de crearlo, puede hacer clic derecho en cualquier carpeta y seleccionar New-->AIDL-->AIDL File, al editar el nombre del archivo, se generará automáticamente en src/Cree un nuevo directorio aidl debajo del directorio main, la estructura del directorio del paquete es como sigue:

main
aidl
com.example.tee.testapplication.aidl
java
com.example.tee.testapplication
res
AndroidManifest.xml

The automatically generated aidl file is as follows:

// AidlInterface.aidl
paquete com.example.tee.testapplication.aidl;
// Declarar cualquier no-definir tipos aquí con declaraciones de importación
interface AidlInterface {
 /**
 * Demonstrates some basic types that you can use as parameters
 * and return values in AIDL.
 */
 void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
 double aDouble, String aString);
}

Podemos ver que el formato del código del archivo aidl es muy similar al de java, admite tipos básicos de java y List, Map, etc., si es una clase personalizada,则需要手动导入,我们后面再说,先来看最简单的,crea un archivo IMyAidlInterface.aidl y modifica como sigue:

paquete com.example.tee.testapplication.aidl;
interface IMyAidlInterface {
 String getValue();
}

Defina un método getValue en la interfaz, que devuelve una cadena, ahora puede compilar el proyecto, encontrar app/construir/generado/fuente/aidl/El directorio debug, debajo del nombre del paquete de nuestra aplicación, encontrará una clase Interface, con el nombre igual al archivo aidl definido, lo que significa que realmente el archivo aidl se convertirá en una interfaz para implementar, y este archivo no necesita ser mantenido por nosotros, se generará automáticamente después de la compilación.

Luego, cree una nueva clase que herede de Service:

public class MAIDLService extends Service{
 public class MAIDLServiceImpl extends IMyAidlInterface.Stub{
 @Override
 public String getValue() throws RemoteException {
 return "get value";
 }
 }
 @Nullable
 @Override
 public IBinder onBind(Intent intent) {
 return new MAIDLServiceImpl();
 }
}

En la clase interna definida en MAIDLService que hereda de IMyAidlInterface.Stub, se sobrescribe el método getValue definido en aidl, es decir, en la interfaz, que devuelve la cadena get value.

Llegados a este punto, hemos creado este servicio de servidor, que tiene la función de devolver una cadena después de la llamada, finalmente, en el archivo AndroidManifest declarar:

<service
 android:name=".MAIDLService"
 android:process=":remote"//con esta línea, la llamada del cliente creará un nuevo proceso
 android:exported="true"//por defecto es true, se puede eliminar, declarar si se puede llamar de forma remota
 >
 <intent-filter>
 <category android:name="android.intent.category.DEFAULT"> />
 <action android:name="com.example.tee.testapplication.aidl.IMyAidlInterface"> />
 </intent-filter>
</service>

La línea android:process=":remote" se utiliza para declarar si se crea un nuevo proceso al llamar, a continuación, escribir el código del cliente, crear un nuevo proyecto, copiar el archivo aidl recién creado a este proyecto, prestando atención también a que debe estar ubicado en la carpeta aidl, luego en MainActivity escribir el código siguiente:

public class MainActivity extends AppCompatActivity {
 private TextView mValueTV;
 private IMyAidlInterface mAidlInterface = null;
 private ServiceConnection mServiceConnection = new ServiceConnection() {
 @Override
 public void onServiceConnected(ComponentName name, IBinder service) {
 mAidlInterface = IMyAidlInterface.Stub.asInterface(service);
 }
 @Override
 public void onServiceDisconnected(ComponentName name) {
 }
 };
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 Intent intent = new Intent("com.example.tee.testapplication.aidl.IMyAidlInterface");
 bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
 mValueTV = (TextView) findViewById(R.id.tv_test_value);
 mValueTV.setOnClickListener(new View.OnClickListener() {
 @Override
 public void onClick(View v) {
 try {
  mValueTV.setText(mAidlInterface.getValue());
 } catch (RemoteException e) {
  e.printStackTrace();
 }
 }
 });
 }
 @Override
 protected void onDestroy() {
 if(mAidlInterface != null){
 unbindService(mServiceConnection);
 }
 super.onDestroy();
 }
}

Tenga en cuenta que la cadena de parámetros que se transmite al crear Intent se define en el action etiqueta personalizada en el manifest, y recuerde desvincular el servicio en onDestroy.

El resultado de la ejecución es que al hacer clic en TextView se mostrará la cadena get value devuelta por el lado del servidor

Objeto personalizado

Recientemente hemos utilizado tipos básicos de String, cuando utilizamos nuestras propias clases definidas, el método anterior no es aplicable. Al usar nuestras clases personalizadas, se debe importar manualmente, modificar el proyecto que creamos como el lado del servidor

Primero, en el paquete generado al inicio (todos los archivos relacionados con aidl deben colocarse en este paquete), crear un nuevo archivo Student.java

public class Student implements Parcelable{
 public String name;
 public int age;
 protected Student(Parcel in) {
 readFromParcel(in);
 }
 public Student() {
 }
 public static final Creator<Student> CREATOR = new Creator<Student>() {
 @Override
 public Student createFromParcel(Parcel in) {
 return new Student(in);
 }
 @Override
 public Student[] newArray(int size) {
 return new Student[size];
 }
 };
 @Override
 public int describeContents() {
 return 0;
 }
 @Override
 public void writeToParcel(Parcel dest, int flags) {
 dest.writeInt(age);
 dest.writeString(name);
 }
 public void readFromParcel(Parcel in){
 age = in.readInt();
 name = in.readString();
 }
 @Override
 public String toString() {
 return String.format(Locale.ENGLISH, "STUDENT[%s:%d]", name, age);
 }
}

Necesita implementar la interfaz de serialización Parcelable, AndroidStudio generará automáticamente la clase interna estática CREATOR y el método describeContents, estas partes no necesitan modificarse, utilice las generadas automáticamente. Luego, sobrescriba el método writeToParcel y defina el método readFromParcel, preste atención a que la secuencia de atributos en estos dos métodos debe ser idéntica, uno es para escribir y el otro para leer. En el constructor Student(Parcel in), llame al método readFromParcel(in).

A continuación, cree un archivo Student.aidl nuevo (también en el paquete aislamiento):

// Student.aidl
paquete com.example.tee.testapplication.aidl;
// Declarar cualquier no-definir tipos aquí con declaraciones de importación
parcelable Student;

Tenga en cuenta que la palabra clave parcelable antes de Student es minúscula, aquí está el archivo IMyAidlInterface.aidl modificado:

// IMyAidlInterface.aidl
paquete com.example.tee.testapplication.aidl;
// Declarar cualquier no-definir tipos aquí con declaraciones de importación
import com.example.tee.testapplication.aidl.Student;
interface IMyAidlInterface {
 Student getStudent();
 void setStudent(in Student student);
 String getValue();
}

Definieron dos métodos, uno para establecer Student y otro para obtener Student, en el método setStudent, preste atención a que el parámetro tiene una palabra clave in antes del tipo, en el aislamiento de los parámetros se dividen en entrada, salida

Ahora, en MAIDLService.java, reescribe los dos métodos nuevos adicionados:}

private Student mStudent;
public class MAIDLServiceImpl extends IMyAidlInterface.Stub{
 @Override
 public Student getStudent() throws RemoteException {
 devolver mStudent;
 }
 @Override
 public void setStudent(Student student) throws RemoteException {
 mStudent = student;
 }
 @Override
 public String getValue() throws RemoteException {
 devolver "get value : " + Thread.currentThread().getName(); + Thread.currentThread().getId();
 }
}

El código del servidor se ha modificado, ahora vamos al proyecto del cliente, también copie y sobrescriba los archivos del paquete aidl anterior para mantener la consistencia de ambos lados, luego modifique el siguiente en MainActivity.java:

mValueTV = (TextView) findViewById(R.id.tv_test_value);
mStudentTV = (TextView) findViewById(R.id.tv_test_student);
mValueTV.setOnClickListener(new View.OnClickListener() {
 @Override
 public void onClick(View v) {
 try {
 mValueTV.setText(mAidlInterface.getValue());
 } catch (RemoteException e) {
 e.printStackTrace();
 }
 }
});
mStudentTV.setOnClickListener(new View.OnClickListener() {
 @Override
 public void onClick(View v) {
 try {
 Student student = new Student();
 student.age = 10;
 student.name = "Tom";
 mAidlInterface.setStudent(student);
 mStudentTV.setText(mAidlInterface.getStudent().toString());
 } catch (RemoteException e) {
 e.printStackTrace();
 }
 }
});

Al compilar el proyecto, se descubrirá que el proyecto reportará errores, no encontrando la clase Student. Necesitamos agregar el código siguiente al archivo build.gradle en la carpeta app:

android {
 sourceSets {
 main {
 manifest.srcFile 'src/main/AndroidManifest.xml'
 java.srcDirs = ['src/main/java, 'src/main/aidl
 resources.srcDirs = ['src/main/java, 'src/main/aidl
 aidl.srcDirs = ['src/main/aidl
 res.srcDirs = ['src/main/res
 assets.srcDirs = ['src/main/assets
 }
 }
}

Es decir, especifique la carpeta de archivos, ya no habrá problemas al compilar ahora

Resumen

El uso de IPC en Android es bastante simple, la sintaxis del archivo AIDL es muy similar a la que usamos cuando utilizamos interfaces, pero solo admite tipos básicos, puede referirse a archivos AIDL y, cuando necesita usar clases personalizadas, es un poco más complicado.

¡Aquí está la recopilación de información sobre la comunicación de procesos IPC en Android! Continuaremos complementando la información relevante, ¡gracias por su apoyo a este sitio!

Declaración: El contenido de este artículo se ha obtenido de la red, es propiedad del autor original, el contenido ha sido contribuido y subido por los usuarios de Internet, este sitio no posee los derechos de propiedad, no ha sido editado por humanos y no asume responsabilidad alguna por las responsabilidades legales. Si encuentra contenido sospechoso de infracción de derechos de autor, por favor envíe un correo electrónico a: notice#oldtoolbag.com (al enviar un correo electrónico, reemplace # con @) para denunciar y proporcionar evidencia relevante. Una vez verificada, este sitio eliminará inmediatamente el contenido sospechoso de infracción.

Te gustaría probar