[Android] Binder (1) Introdução do Binder e exemplos de uso do Binder em AIDL

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
insira a descrição da imagem aqui
depois crie o arquivo AIDL

Nota: aidlA pasta precisa ser criada sozinha, e a pasta está mainabaixo da pasta, que está javano mesmo nível da pasta

insira a descrição da imagem aqui

Quando aidlcriamos o arquivo aidl na pasta, encontramos este erro:
insira a descrição da imagem aqui

Este prompt significa que você precisa definir buildFeatures.aidl como true no arquivo build.gradle para usar a tecnologia AIDL
insira a descrição da imagem aqui

 buildFeatures {
    
    
    aidl = true
 }

aidlNeste 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.
insira a descrição da imagem aqui
Então precisamos implementar o método de interface e registrá-lo no sistema, aqui utilizamos um Serviço para conseguir:
insira a descrição da imagem aqui
insira a descrição da imagem aqui
insira a descrição da imagem aqui

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:
insira a descrição da imagem aqui
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.xmladicionar 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

MyServiceAo 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
insira a descrição da imagem aqui
código AIDL Código gerado:
insira a descrição da imagem aqui

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

insira a descrição da imagem aqui

cliente

insira a descrição da imagem aqui

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 MyBindere há apenas um arquivo

insira a descrição da imagem aqui

Código da atividade principal

insira a descrição da imagem aqui
insira a descrição da imagem aqui
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 服务端
insira a descrição da imagem aqui
e depois começar novamente 客户端
insira a descrição da imagem aqui
. Depois de se conectar ao servidor, o servidor exibirá
insira a descrição da imagem aqui
e chamará o método no cliente getCurrentTimestamppara obter dados:
insira a descrição da imagem aqui
observe o servidor neste ponto. Até
insira a descrição da imagem aqui
agora, um AIDL simples usando Binder cross -a comunicação do processo está concluída.

Acho que você gosta

Origin blog.csdn.net/qq_43358469/article/details/130981992
Recomendado
Clasificación