バインダーの紹介
Android の Binder は、異なるプロセスがメソッドを呼び出し、相互にデータを転送できるようにするプロセス間通信メカニズムです。Binder は主にシステムサービスとアプリケーション間の通信や IPC (Inter-Process Communication、プロセス間通信) の実装に使用されます。
Binder の中核は Binder ドライバーであり、異なるプロセス間の通信の管理を担当します。各プロセスはサービス プロバイダーとして独自の Binder オブジェクトを作成でき、他のプロセスがクライアントとして提供する Binder オブジェクトを取得することもできます。これらの Binder オブジェクトは、プロセス間通信のために Binder によって駆動される必要があります。
観点机制
: Binder はプロセス間通信メカニズムです
観点驱动
: Binder は仮想物理デバイスドライバーです
観点应用层
: Binder は通信を開始できる Java クラスです
Android 開発では、AIDL (Android Interface Definition Language) を通じて独自の Binder インターフェイスを定義し、対応するサービス プロバイダーとクライアントを実装できます。AIDL によって生成されたコードは、異なるプロセス間の IPC 通信に使用できます。
Binder と他のプロセス通信方式の比較
Binder と従来の IPC の比較 | |||
---|---|---|---|
バインダー | 共有メモリ | ソケット | |
パフォーマンス | 一度コピーする必要がある | コピーする必要はありません | 2回コピーする必要がある |
特徴 | C/Sアーキテクチャをベースとした高いユーザビリティ | 操作が複雑で操作性が悪い | C/Sアーキテクチャを採用しており、汎用インタフェースとしては伝送効率が低く、オーバーヘッドが大きい |
安全性 | 各アプリに UID を割り当て、実名と匿名の両方をサポートします | 上位層のプロトコル アクセスに依存しているため、アクセス ポイントはオープンで安全ではありません |
バインダー機構構成
バインダー (IInterface インターフェース) | このクラスは、クライアントとサーバー間の通信のためのリモート サービス インターフェイスを定義します。 |
IBinderインターフェース | このクラスは、軽量のプロセス間通信機能を提供する Binder の実装クラスです。 |
サービスマネージャ | このクラスは、バインダー サービスを登録および検索するためのメカニズムを提供します。 |
バインダードライバー | ドライバーは Binder のプロセス間通信の中核であり、Binder の接続、データ送信、スレッド、その他の操作を管理するために使用されます。 |
Binder メカニズムは、Android 開発に効率的かつ柔軟なプロセス間通信方法を提供し、アプリケーションがプロセス間でデータを共有したり、リモート サービスを呼び出したりすることを容易にします。
AIDLとバインダーの関係
AIDL (Android Interface Definition Language、Android インターフェイス定義言語) は、Android システムでプロセス間通信 (IPC) を実装するために使用されるメカニズムです。AIDL は、開発者が異なるアプリケーション間または異なるプロセス間でリモート メソッド呼び出しを実装し、プロセス間のデータ共有と対話を実現するのに役立ちます。
Binder は、Android システムに IPC を実装するためのコア ドライバーであり、AIDL で定義されたインターフェイスの基礎的なサポートを提供できます。バインダードライバーは、プロセス間の接続やデータ送信などを管理することで、AIDLに基づくプロセス間通信機能を実現します。
AIDL と Binder の関係は次のように理解できます。AIDL はプロセス間通信インターフェイスを記述するための言語を提供し、Binder は AIDL インターフェイス呼び出しを実装するための内部フレームワークです。Androidアプリケーションでは一般に、AIDLファイルにクロスプロセスアクセスのためのインターフェースを定義し、それをBinderを通じて実装することでアプリケーション間の通信を実現しています。
Binderを使用したプロセス間通信の例
服务端
まず、とという 2 つの端末を作成する必要があります。客户端
サーバ
という名前のプロジェクトを作成し、MyBinderService
AIDL ファイルを作成します。
注:aidl
フォルダーは独自に作成する必要があり、フォルダーはmain
フォルダーの下にあり、java
フォルダーと同じレベルにあります。
aidl
フォルダー内に Aidl ファイルを作成したときに、次のエラーが発生しました。
このプロンプトは、AIDL テクノロジを使用するには、build.gradle ファイルで buildFeature.aidl を true に設定する必要があることを意味します。
buildFeatures {
aidl = true
}
この時点で、上のaidl
フォルダーの色も変わっていることがわかります。
サーバー アプリケーションでは、クライアントにデータ取得方法を提供する AIDL インターフェイスを定義する必要があります。
次に、インターフェイス メソッドを実装してシステムに登録する必要があります。ここではサービスを使用して次のことを実現します。
完全なコード
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;
}
}
メインページ:
完全なコード:
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);
}
});
}
}
知らせ:
AndroidManifest.xml
この権限をファイルに追加する必要があります。
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
それ以外の場合は、エラーが報告されます。
Permission Denial: startForeground from pid=16363, uid=10134 requires android.permission.FOREGROUND_SERVICE
同時に、このファイルに完璧なMyService
ファイルを登録します
<service
android:name=".MyService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.shsany.mybinderservice"/>
</intent-filter>
</service>
この時点で構成した後、Android Studio が AIDL コードを自動的に生成するように、忘れずにプロジェクトをビルドしてください。
生成されたコード:
クライアント
クライアント側で設定する必要がある手順と方法はサーバー側と同じであるため、ここでは説明しません。
知らせ:
AIDL ファイルはクライアント側で書き換えず、サーバー側からコピーして、両側が同じであることを確認します。
サーバ
クライアント
両端のファイルはパッケージ名と内部のコードが同じであるため、直接コピーすることをお勧めします。
クライアントの名前はMyBinder
、ファイルは 1 つだけです
MainActivity コード
完全なコード:
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;
}
};
}
テスト
服务端
まず、開始してから再度開始する必要があります客户端
。サーバーに接続した後、サーバーが表示され、
クライアントでメソッドを呼び出してgetCurrentTimestamp
データを取得します。
この時点でサーバーを見てください。これまでのところ
、Binder クロスを使用した単純な AIDL -プロセス通信が完了しました。