インターネットの巨人は「バインダー」について何を尋ねますか?尋ねるのはどれくらい深いですか?
誰もが私と同じくらい好奇心が強いと思います。「バインダー」の技術の多くは大手インターネット企業のプロジェクトでしか使えないのですが、塩漬けになりたくなくて、まだBATに憧れています。来年の春の採用で勝ちたいので。年末レビューの概要は、主にインタビューに関連する技術的な知識ポイントに基づいています。私と同じ考えを持っている友人は、私がGithubで数か月過ごした「Androidインタビューのコア知識ポイント」を参照できます。
インタビューリファレンス
この記事では、主に私がまとめたインタビューの質問の方法でバインダーのメカニズムを説明します。それを書くことができれば、好きなものを残してください。
- プロセス間のコミュニケーション方法を分析する
- バインダーのプロキシクラスは動的プロキシを使用します。コアメソッド:mRotate.transact(Stub.TRANSACTION_xxx、_data、_reply、flags);
- バインダーの利点は何ですか?(バイトビートの本当の質問)
- バインダーはどのようにして1つのコピーを作成しますか?(10の本当の質問)
- MMAPの原理の説明;(10の本当の質問)
- AIDLによって生成されたJavaクラスの詳細を説明してください;(バイトビートの実際の質問)
- 4つの主要コンポーネントの下部にある通信メカニズム;(バイトビートの実際の質問)
- インテントがビッグデータを配信できないのはなぜですか?(アリ・ゼンティ)
プロセス間通信方式
共有メモリ、ソケット、パイプなど、プロセス間通信には多くの方法がありますが、これらをAndroid開発として使用することはありません(後で調査する必要がある場合は、これを理解していません)。 Androidバインダーを使用しています。違いは以下のように。
バインダーを使用する利点:
- 1.コピーは1回で済みます。コピーを必要としない通信メカニズムはありますが、常に情報リソースの同期が必要です。これは非常にパフォーマンスが高く、制御が非常に複雑で、簡単です。使い勝手も悪いです。
- 2.セキュリティ。各アプリにはUIDが割り当てられているため(アプリケーションIDと見なすことができます)。
メモリパーティション
データの転送方法を知りたい、あなたはメモリ分割を理解する必要があります
バインダーと従来のIPCはどのようにデータを転送しますか?
従来のipc(プロセス間通信メカニズム)と比較したバインダー。従来のipc
送信データフロー
。1つのコピー:
サーバー側のスペース(仮想メモリ)とカーネルスペース(仮想メモリ)が同じ物理メモリにマップされます。 MMPを介して。コピーする必要はありません:送信者、受信者、共有領域は同じ物理メモリにマップされます(さまざまな情報リソースの同期が必要になるため、制御が複雑になり、使いやすさが低下します)
上層はAIDLを介してAndroid側でプロセス通信を実装し、下層はバインダーを使用し、AIDLはプロセス間通信プロセスを実装します
ははは、この写真は私自身が描いたもので、プロセス間通信の解釈は非常に徹底していると思います。上層はAIDL、下層はバインダー、クライアントのプロキシクラスはデータを送信し、ServiceManager(それ自体はサービス)クラスは適切なサーバーサービスを見つけるために使用され、サービス(サービス)はAIDLに対応する必要があり、サーバーのサービススタブがデータを受信し、サーバーのプロキシがデータをクライアントに送信します。\ color {#FF0000} {上層はAIDL、下層はBinder、クライアントのプロキシクラスデータを送信するには、ServiceManager(サービス)クラスを介して適切なサーバーサービスを見つけます。サービス(サービス)はに対応する必要があります。 AIDL、サーバーのサービススタブがデータを受信し、サーバーのプロキシがデータをクライアントに送信するなど)。これはAIDLであり、最下層はBinderであり、クライアントのプロキシクラスがデータを送信します。適切なサーバーサービスは、ServiceManager(それ自体がService)クラスを介して検出されます。サービス(Service)はAIDLに対応する必要があり、サーバーのサービススタブがデータを受信すると、サーバーのプロキシがクライアントにデータを送信します。そして、ライン全体が完成しました。
クライアントはAIDLハンドルをどのように取得し、このハンドルを介してサーバーを呼び出す方法、およびサーバーはそれをどのように処理しますか?
デモ例
- 1.エンジニアリング構造
サーバ
クライアント
- 2.コード
新しいaidlファイルを作成する方法については説明しません。これが基本です。
サーバ
//1.ILiaoAidlInterface
package com.xm.aidl_server;
// Declare any non-default types here with import statements
import com.xm.aidl_server.Person;
interface ILiaoAidlInterface {
List<Person> getPersonList();
void addPerson(in Person person);
}
--------------------------------
//2.Person aidl文件
package com.xm.aidl_server;
parcelable Person;
-------------------
//3.Person对应的实体类
package com.xm.aidl_server;
import android.os.Parcel;
import android.os.Parcelable;
//1.Android开发:什么是Parcel? http://blog.csdn.net/nkmnkm/archive/2011/05/28/6451699.aspx
//2.android开发之Parcelable使用详解 https://blog.csdn.net/u012702547/article/details/47151001/
public class Person implements Parcelable {
private String name;
private int grade;
public Person(String name, int grade) {
this.name = name;
this.grade = grade;
}
protected Person(Parcel in) {
this.name = in.readString();
this.grade = in.readInt();
}
public static final Creator<Person> CREATOR = new Creator<Person>() {
@Override
public Person createFromParcel(Parcel in) {
return new Person(in);
}
@Override
public Person[] newArray(int size) {
return new Person[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(grade);
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", grade=" + grade +
'}';
}
}
-------------------------
//4.服务端app对应的服务(Service)类
package com.xm.aidl_server;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.Nullable;
public class MyService extends Service {
private List<Person> personList;
@Nullable
@Override
public IBinder onBind(Intent intent) {
personList = new ArrayList<>();
return iBinder;
}
private IBinder iBinder = new ILiaoAidlInterface.Stub() {
@Override
public List<Person> getPersonList() throws RemoteException {
return personList;
}
@Override
public void addPerson(Person person) throws RemoteException {
personList.add(person);
}
};
}
--------------------------------
//5.启动服务端app的Service
public class MainActivity extends AppCompatActivity {
private Intent intent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intent = new Intent(this, MyService.class);
startService(intent);
}
@Override
protected void onDestroy() {
super.onDestroy();
stopService(intent);
}
}
以上がサーバー側のコードです。もともとスクリーンショットを撮りたかったのですが、このブログを見ている人がすぐに始められるのではないかと心配して投稿しました。
クライアント
このコードはサーバーからコピーされます。プロセス間通信を実現するには、このコードに一貫性が必要です。!!
Button btn = findViewById(R.id.btn);
//1.第一步 绑定服务端service
bindService();
//第二步 设置按钮点击事件
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
iLiaoAidlInterface.addPerson(new Person("姓名",7));
List<Person> personList = iLiaoAidlInterface.getPersonList();
Log.i("MainActivity", "onClick: "+personList.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
---------------------------------------
//2.bindService()方法
private void bindService() {
Intent intent = new Intent();
//todo 为啥不能直接通过intent带参数 为啥非得这种方式 全包名、类名
intent.setComponent(new ComponentName("com.xm.aidl_server","com.xm.aidl_server.MyService"));
//todo 三个参数都得介绍
//service 指的是服务端service
//
//参数三:flags: 为0,表示客户端可以发送到服务端,服务端也可以返回 为1,表示客户端发送到服务端,但是服务端不可以返回
//_data:是客户端发送到服务端 _reply:是服务端可以发送到客户端
bindService(intent,connection,0);
}
----------------------------------------------
// 3.内部类connection
ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//todo
iLiaoAidlInterface = ILiaoAidlInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
//todo
iLiaoAidlInterface = null;
}
};
出力
//场景1:服务端Service如果没有开启 点击客户端按钮 日志如下
2020-12-26 23:42:32.821 10001-10001/com.xm.aidl_client W/System.err: at com.xm.aidl_client.MainActivity$1.onClick(MainActivity.java:33)
2020-12-26 23:42:54.203 10001-10001/com.xm.aidl_client W/System.err: at com.xm.aidl_client.MainActivity$1.onClick(MainActivity.java:33)
2020-12-26 23:43:08.919 10001-10001/com.xm.aidl_client W/System.err: at com.xm.aidl_client.MainActivity$1.onClick(MainActivity.java:33)
-----------------------------------------------------------
//场景2:服务端Service如果开启 点击客户端按钮 日志如下
2020-12-26 23:44:59.928 13635-13635/com.xm.aidl_client I/MainActivity: onClick: [Person{name='姓名', grade=7}]
2020-12-26 23:45:01.761 13635-13635/com.xm.aidl_client I/MainActivity: onClick: [Person{name='姓名', grade=7}, Person{name='姓名', grade=7}]
2020-12-26 23:45:04.672 13635-13635/com.xm.aidl_client I/MainActivity: onClick: [Person{name='姓名', grade=7}, Person{name='姓名', grade=7}, Person{name='姓名', grade=7}]
AプロセスがBプロセスにアクセスするときのいくつかの状態
- 1.プロセスBが開始されていない
- 2.プロセスBは開始されますが、サービスは作成されません
- 3.プロセスBが開始され、サービスが作成されますが、サービスはバインドされていません。コールバックonBind()
- 4.プロセスBが開始され、サービスが作成されますが、サービスはバインドされ、コールバックonRebind()