Introdução ao fichário
Binder no Android é um mecanismo de comunicação entre processos que permite que diferentes processos chamem métodos e transfiram dados entre si. O Binder é usado principalmente para implementar a comunicação entre serviços e aplicativos do sistema e para implementar IPC (Comunicação entre processos, comunicação entre processos).
O núcleo do Binder é o driver Binder, responsável por gerenciar a comunicação entre os diferentes processos. Cada processo pode criar seu próprio objeto Binder como provedor de serviços ou obter objetos Binder fornecidos por outros processos como cliente. Esses objetos Binder devem ser controlados pelo Binder para comunicação entre processos.
Do 机制
ponto de vista: Binder é um mecanismo de comunicação entre processos
Do 驱动
ponto de vista: Binder é um driver de dispositivo físico virtual
Do 应用层
ponto de vista: Binder é uma classe Java que pode iniciar a comunicação
No desenvolvimento Android, podemos definir nossa própria interface Binder através de AIDL (Android Interface Definition Language) e implementar o provedor de serviços e cliente correspondente. O código gerado pelo AIDL pode ser usado para comunicação IPC entre diferentes processos.
Comparação do Binder e outros esquemas de comunicação de processo
Comparação entre Binder e IPC tradicional | |||
---|---|---|---|
Encadernador | Memoria compartilhada | Soquete | |
desempenho | preciso copiar uma vez | não há necessidade de copiar | preciso copiar duas vezes |
características | Baseado na arquitetura C/S, alta usabilidade | Controles complicados e pouca usabilidade | Baseado na arquitetura C/S, como interface de uso geral, sua eficiência de transmissão é baixa e a sobrecarga é grande |
segurança | Atribua um UID a cada APP, suportando nomes reais e anônimos | Confie no acesso ao protocolo da camada superior, o ponto de acesso é aberto e inseguro |
Composição do mecanismo de encadernação
Fichário (interface IInterface) | Esta classe define a interface de serviço remoto para comunicação entre o cliente e o servidor |
Interface IBinder | Esta classe é a classe de implementação do Binder, que fornece recursos leves de comunicação entre processos |
Gerenciador de serviços | Esta classe fornece um mecanismo para registrar e localizar serviços Binder |
Driver de fichário | O driver é o núcleo da comunicação entre processos do Binder e é usado para gerenciar conexões do Binder, transmissão de dados, threads e outras operações |
O mecanismo Binder fornece um método de comunicação entre processos eficiente e flexível para o desenvolvimento Android, tornando mais fácil para os aplicativos compartilharem dados entre processos e chamarem serviços remotos.
A relação entre AIDL e Binder
AIDL (Android Interface Definition Language, Android Interface Definition Language) é um mecanismo usado para implementar a comunicação entre processos (IPC) no sistema Android. AIDL pode ajudar os desenvolvedores a implementar chamadas de métodos remotos entre diferentes aplicativos ou entre diferentes processos, de modo a realizar o compartilhamento e a interação de dados entre processos.
O Binder é o principal driver para a implementação do IPC no sistema Android e pode fornecer o suporte subjacente para as interfaces definidas pelo AIDL. O driver Binder completa a função de comunicação entre processos baseada em AIDL, gerenciando a conexão entre processos, transmissão de dados e outras operações.
A relação entre AIDL e Binder pode ser entendida como: AIDL fornece uma linguagem para descrever interfaces de comunicação entre processos, enquanto Binder é uma estrutura interna para implementar chamadas de interface AIDL. Em uma aplicação Android, geralmente, as interfaces para acesso entre processos são definidas no arquivo AIDL, e essas interfaces são implementadas através do Binder, de forma a realizar a comunicação entre as aplicações.
Exemplo de uso do Binder para comunicação entre processos
Primeiro, precisamos criar dois terminais, a saber 服务端
e客户端
Servidor
Crie um projeto chamado e MyBinderService
depois crie o arquivo AIDL
Nota: aidl
A pasta precisa ser criada sozinha, e a pasta está main
abaixo da pasta, que está java
no mesmo nível da pasta
Quando aidl
criamos o arquivo aidl na pasta, encontramos este erro:
Este prompt significa que você precisa definir buildFeatures.aidl como true no arquivo build.gradle para usar a tecnologia AIDL
buildFeatures {
aidl = true
}
aidl
Neste ponto vemos que a pasta acima também mudou de cor.
Na aplicação do servidor, precisamos definir uma interface AIDL para fornecer ao cliente um método de aquisição de dados.
Então precisamos implementar o método de interface e registrá-lo no sistema, aqui utilizamos um Serviço para conseguir:
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);
}
});
}
}
Perceber:
Precisa AndroidManifest.xml
adicionar esta permissão no arquivo:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
Caso contrário, um erro será relatado:
Permission Denial: startForeground from pid=16363, uid=10134 requires android.permission.FOREGROUND_SERVICE
MyService
Ao mesmo tempo, registre o arquivo perfeito neste arquivo
<service
android:name=".MyService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.shsany.mybinderservice"/>
</intent-filter>
</service>
Após configurar neste momento, lembre-se de construir o projeto, para que o Android Studio gere automaticamente o
código AIDL Código gerado:
cliente
As etapas e métodos que precisam ser configurados no lado do cliente são os mesmos do lado do servidor e não serão descritos aqui.
Perceber:
Não reescreva o arquivo AIDL no lado do cliente, mas copie-o do lado do servidor para garantir que ambos os lados sejam iguais.
Servidor
cliente
Os arquivos em ambas as extremidades têm o mesmo nome de pacote e o mesmo código interno, portanto é melhor copiá-los diretamente.
O cliente é nomeado MyBinder
e há apenas um arquivo
Código da atividade 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;
}
};
}
teste
Primeiro, você precisa iniciar 服务端
e depois começar novamente 客户端
. Depois de se conectar ao servidor, o servidor exibirá
e chamará o método no cliente getCurrentTimestamp
para obter dados:
observe o servidor neste ponto. Até
agora, um AIDL simples usando Binder cross -a comunicação do processo está concluída.