Introducción a la carpeta
Binder en Android es un mecanismo de comunicación entre procesos que permite que diferentes procesos llamen a métodos y transfieran datos entre sí. Binder se utiliza principalmente para implementar la comunicación entre servicios y aplicaciones del sistema, y para implementar IPC (comunicación entre procesos, comunicación entre procesos).
El núcleo de Binder es el controlador Binder, que es responsable de gestionar la comunicación entre diferentes procesos. Cada proceso puede crear su propio objeto Binder como proveedor de servicios y también puede obtener objetos Binder proporcionados por otros procesos como clientes. Estos objetos de Binder deben ser controlados por Binder para la comunicación entre procesos.
Desde 机制
la perspectiva: Binder es un mecanismo de comunicación entre procesos
Desde 驱动
la perspectiva: Binder es un controlador de dispositivo físico virtual
Desde 应用层
la perspectiva: Binder es una clase Java que puede iniciar la comunicación
En el desarrollo de Android, podemos definir nuestra propia interfaz Binder a través de AIDL (lenguaje de definición de interfaz de Android) e implementar el proveedor de servicios y el cliente correspondientes. El código generado por AIDL se puede utilizar para la comunicación IPC entre diferentes procesos.
Comparación de Binder y otros esquemas de comunicación de procesos
Comparación entre Binder y IPC tradicional | |||
---|---|---|---|
Aglutinante | Memoria compartida | Enchufe | |
actuación | necesito copiar una vez | no es necesario copiar | necesito copiar dos veces |
características | Basado en arquitectura C/S, alta usabilidad | Controles complicados y mala usabilidad. | Basado en la arquitectura C/S, como interfaz de uso general, su eficiencia de transmisión es baja y la sobrecarga es grande. |
seguridad | Asigne un UID a cada aplicación, admitiendo tanto nombre real como anónimo | Confíe en el acceso al protocolo de capa superior, el punto de acceso es abierto e inseguro |
Composición del mecanismo aglutinante.
Carpeta (interfaz IInterface) | Esta clase define la interfaz de servicio remoto para la comunicación entre el cliente y el servidor. |
Interfaz IBinder | Esta clase es la clase de implementación de Binder, que proporciona capacidades livianas de comunicación entre procesos. |
Supervisor | Esta clase proporciona un mecanismo para registrar y encontrar servicios de Binder. |
conductor de carpeta | El controlador es el núcleo de la comunicación entre procesos de Binder y se utiliza para administrar conexiones de Binder, transmisión de datos, subprocesos y otras operaciones. |
El mecanismo Binder proporciona un método de comunicación entre procesos eficiente y flexible para el desarrollo de Android, lo que facilita que las aplicaciones compartan datos entre procesos y llamen a servicios remotos.
La relación entre AIDL y Binder
AIDL (lenguaje de definición de interfaz de Android, lenguaje de definición de interfaz de Android) es un mecanismo utilizado para implementar la comunicación entre procesos (IPC) en el sistema Android. AIDL puede ayudar a los desarrolladores a implementar llamadas a métodos remotos entre diferentes aplicaciones o entre diferentes procesos, para lograr el intercambio y la interacción de datos entre procesos.
Binder es el controlador principal para implementar IPC en el sistema Android y puede proporcionar soporte subyacente para las interfaces definidas por AIDL. El controlador Binder completa la función de comunicación entre procesos basada en AIDL al administrar la conexión entre procesos, la transmisión de datos y otras operaciones.
La relación entre AIDL y Binder puede entenderse como: AIDL proporciona un lenguaje para describir interfaces de comunicación entre procesos, mientras que Binder es un marco interno para implementar llamadas de interfaz AIDL. En una aplicación de Android, generalmente, las interfaces para el acceso entre procesos se definen en el archivo AIDL y estas interfaces se implementan a través de Binder para realizar la comunicación entre aplicaciones.
Ejemplo de uso de Binder para comunicación entre procesos
Primero, necesitamos crear dos terminales, a saber 服务端
y客户端
Servidor
Cree un proyecto llamado y MyBinderService
luego cree el archivo AIDL
Nota: aidl
La carpeta debe crearse sola y la carpeta está main
debajo de la carpeta, que está java
al mismo nivel que la carpeta.
Cuando aidl
creamos el archivo Aidl en la carpeta, encontramos este error:
Este mensaje significa que debe configurar buildFeatures.aidl en verdadero en el archivo build.gradle para usar la tecnología AIDL.
buildFeatures {
aidl = true
}
aidl
En este punto vemos que la carpeta de arriba también ha cambiado de color.
En la aplicación del servidor, necesitamos definir una interfaz AIDL para proporcionar al cliente un método de adquisición de datos.
Luego necesitamos implementar el método de interfaz y registrarlo en el sistema. Aquí usamos un Servicio para lograr:
código completo
public class MyService extends Service {
private static final int NOTIFICATION_ID = 1001; // 前台通知 ID
private final IBinder mBinder = new MyBinder();
@Override
public IBinder onBind(Intent intent) {
Log.e("Binder响应:", "已经绑定到Binder上面了");
return mBinder;
}
static class MyBinder extends IMyService.Stub {
@Override
public long getCurrentTimestamp() throws RemoteException {
long time = System.currentTimeMillis();
Log.e("Binder数据:", "服务端的时间戳:" + time);
return time;
}
}
@Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManager manager = getSystemService(NotificationManager.class);
NotificationChannel channel = new NotificationChannel(
"channel_id",
"前台通知渠道名称",
NotificationManager.IMPORTANCE_DEFAULT
);
manager.createNotificationChannel(channel);
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "channel_id")
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle("Binder服务端")
.setContentText("测试Binder的前台Service");
startForeground(NOTIFICATION_ID, builder.build());
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
Log.e("Binder的服务", "在Service做耗时任务的话,请使用子线程,因为Service是在主线程运行的");
Log.e("Binder的服务", "此时的线程:" + Thread.currentThread().getName());
}
}).start();
return START_STICKY;
}
}
Página principal:
Código completo:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tvStartService = findViewById(R.id.tv_startService);
TextView tvStopService = findViewById(R.id.tv_stopService);
tvStartService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, MyService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent);
} else {
startService(intent);
}
}
});
tvStopService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, MyService.class);
stopService(intent);
}
});
}
}
Aviso:
Es necesario AndroidManifest.xml
agregar este permiso en el archivo:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
De lo contrario, se informará un error:
Permission Denial: startForeground from pid=16363, uid=10134 requires android.permission.FOREGROUND_SERVICE
MyService
Al mismo tiempo, registre el archivo perfecto en este archivo.
<service
android:name=".MyService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.shsany.mybinderservice"/>
</intent-filter>
</service>
Después de la configuración en este momento, recuerde compilar el proyecto, para que Android Studio genere automáticamente el
código AIDL Código generado:
cliente
Los pasos y métodos que deben configurarse en el lado del cliente son los mismos que en el lado del servidor y no se describirán aquí.
Aviso:
No reescriba el archivo AIDL en el lado del cliente, cópielo desde el lado del servidor para asegurarse de que ambos lados sean iguales.
Servidor
cliente
Los archivos en ambos extremos tienen el mismo nombre de paquete y el mismo código dentro, por lo que es mejor copiarlos directamente.
El cliente tiene nombre MyBinder
y solo hay un archivo.
Código de actividad principal
Código completo:
public class MainActivity extends AppCompatActivity {
private IMyService mMyService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tvGetData = findViewById(R.id.tv_getBinderData);
Intent intent = new Intent();
intent.setAction("com.shsany.mybinderservice");
intent.setPackage("com.shsany.mybinderservice");
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
tvGetData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try {
// 在使用服务端方法时,先判断服务是否可用
if (mMyService != null) {
long currentTime = mMyService.getCurrentTimestamp();
Log.e("Binder数据:", "从服务端接收到的时间戳:" + currentTime);
} else {
Log.e("Binder数据:", "无法连接到服务端");
}
} catch (Exception e) {
Log.e("Binder错误:", e.getMessage());
}
}
});
}
private final ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
//远程Service绑定
Log.e("Binder数据:", "已经连接到服务端");
mMyService = IMyService.Stub.asInterface(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
//Service被意外销毁
Log.e("Binder数据:", "服务端被意外销毁");
mMyService = null;
}
};
}
prueba
Primero debe comenzar 服务端
y luego comenzar nuevamente 客户端
. Después de conectarse al servidor, el servidor mostrará
y luego llamará al método en el cliente getCurrentTimestamp
para obtener datos:
mire el servidor en este punto. Hasta
ahora, un AIDL simple usando Binder cross -Se completa la comunicación del proceso.