android进阶篇13、进程间通信机制Binder简述

return "book name: " + name;
}

@Override
public int describeContents() {
return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.name);
}

public void readFromParcel(Parcel dest){
name = dest.readString();
}
}

3、以上两步是客户端和服务端进行的同样的操作,下面针对客户端和服务端分别处理;

服务端的处理代码如下,注释1处表示当客户端通过bindService绑定服务端时,服务端会通过onBind方法将IBinder对象返回给客户端,这里返回的对象类型就是AIDL接口文件自动生成的java文件的内部类Stub对象,这个Stud继承了Binder并且实现了步骤1中的BookController接口,因此可以作为IBinder类型对象返回;

注释2处表示我们在服务端Stud的匿名内部类实现了此接口中的两个方法,这样在客户端调用此接口中的方法时就会回调到这里;

public class AIDLService extends Service {
private List bookList;
public AIDLService() {
}
@Override
public IBinder onBind(Intent intent) { //1
return stub;
}

@Override
public void onCreate() {
super.onCreate();
bookList = new ArrayList<>();
Book book = new Book(“算法导论”);
bookList.add(book);
}

private final BookController.Stub stub = new BookController.Stub() { //2
@Override
public List getBookList() {
return bookList;
}

@Override
public void addBookInOut(Book book) {
if (book != null){
book.setName(“服务器改了新书的名字 InOut”);
bookList.add(book);
}
}
};
}

4、客户端的处理代码如下,注释4处的bindService表示客户端与服务端进行绑定,绑定成功会回调到注释1处,我们在注释1处将服务端返回的IBinder对象通过BookController.Stub.asInterface(iBinder)方法获得BookController接口对象,然后在注释2和注释3处调用接口中的两个方法,就会回调到服务端中匿名内部类Stub的内部实现中去;

public class MainActivity extends AppCompatActivity {
private final String TAG = “ClientMainActivity”;
private BookController bookController;
private boolean connected;
private List bookList;

private final ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
bookController = BookController.Stub.asInterface(iBinder); //1
connected = true;
}

@Override
public void onServiceDisconnected(ComponentName componentName) {
connected = false;
}
};

private final View.OnClickListener clickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.btn_getBookList:
if (connected){
try {
bookList = bookController.getBookList(); //2
} catch (RemoteException e) {
e.printStackTrace();
}
log();
}
break;
case R.id.btn_addBook_inout:
if (connected){
Book book = new Book(“这是一本新书”);
try {
bookController.addBookInOut(book); //3
} catch (RemoteException e) {
e.printStackTrace();
}
}
break;
default:
break;
}
}
};

private void log() {
for (Book book: bookList){
Log.e(TAG, book.toString());
}
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

findViewById(R.id.btn_getBookList).setOnClickListener(clickListener);
findViewById(R.id.btn_addBook_inout).setOnClickListener(clickListener);
bindServices(); //4
}

private void bindServices() {
Intent intent = new Intent();
try {
intent.setPackage(“com.sunnyweather.android”);
intent.setAction(“com.sunnyweather.android.action”);
bindService(intent,serviceConnection,BIND_AUTO_CREATE);
} catch (Exception e) {
e.printStackTrace();
}
}

@Override
protected void onDestroy() {
super.onDestroy();
if (connected){
unbindService(serviceConnection);
}
}
}

二、进程间通信

1、方式介绍:

进程间通信的方式有共享内存、Binder、Socket、管道、信号量等,各种方式特点如下:

共享内存:数据无需拷贝;但控制复杂,易用性差;访问接入点是开放的,不安全;

Binder:数据拷贝一次;基于C/S架构,易用性好;为每个APP分配UID,同时支持实名和匿名,安全性好;

Socket等其他方式:数据拷贝两次;效率低,开销大;访问接入点是开放的,不安全;

综上所述,Android进程间通信选用的是Binder;

2、内存划分:

内存被操作系统划分为两块,用户空间和内核空间,他们之间是相互隔离的,用户空间专门存放用户程序代码运行的地方,内核空间是内核代码运行的地方;这样即使用户程序崩溃了内核也不会受影响;

32位操作系统的寻址空间为2^32,即总共可访问地址为4G;内核为1G,用户空间为3G;

64位操作系统,低位0-47位才是有效的可变地址(256T),高位48-63位全补0对应的寻址空间是用户空间,高位48-63位全补1对应的寻址空间是内核空间;

3、传统IPC传输数据:

传统IPC在进程之间传输数据时需要拷贝两次;内核空间首先调用copy_from_user()将数据从用户空间拷贝到内核缓存区(第一次拷贝),然后内核空间调用copy_to_user()将数据从内核缓存区拷贝到用户空间(第二次拷贝);

4、Binder传输数据:

Binder在进程之间传输数据时仅需要拷贝一次;首先内核空间通过copy_from_user()将数据拷贝到一块物理内存区域,然后内核空间将自己的一块虚拟空间指向该物理内存,最后接收方用户进程通过mmap()将其虚拟内存指向该物理内存,便可以直接使用该物理内存中的数据了,这样也就实现了仅需一次拷贝;

mmap:Linux通过将一个虚拟内存区域与一个物理内存区域关联起来,以初始化这个虚拟内存区域的内容,这个过程称为内存映射(memory mapping),简称mmap;对文件进行mmap,会在进程的虚拟内存分配地址空间,创建映射关系,实现这样的映射关系后,就可以通过指针的方法读写操作这一段内存,而系统会自动回写到对应的文件磁盘上;

三、Binder框架

1、简介

Binder框架可分为Client端和Server端,根据层级又会分为FrameWork层,JNI层,Native层和Kernel驱动层;

FrameWork层在客户端和服务端的代表是BinderProxy和Binder;Native层在客户端和服务端的代表是BpBinder和BBinder;

2、Binder内核驱动层

在Binder驱动层,主要会调用四个方法:

binder_init 创建dev/binder设备节点

binder_open 获取Binder Drive的文件描述符

binder_mmap 在内核分配一块内存,用于存放数据

binder_ioctl 将IPC数据作为参数传递给Binder Drive

binder_ioctl_write_read 这个方法是binder_ioctl比较重要的方法,在数据读写的时候经常调用

binder_thread_write 进行写操作时调用的方法

binder_thread_read 进行读操作时调用的方法

3、传输的数据在内核层的大小限制为4M,应用层限制为1M-8K;

最后说一下我的学习路线

其实很简单就下面这张图,含概了Android所有需要学的知识点,一共8大板块:

  1. 架构师筑基必备技能
  2. Android框架体系架构(高级UI+FrameWork源码)
  3. 360°Androidapp全方位性能调优
  4. 设计思想解读开源框架
  5. NDK模块开发
  6. 移动架构师专题项目实战环节
  7. 移动架构师不可不学习微信小程序
  8. 混合开发的flutter

Android学习的资料

我呢,把上面八大板块的分支都系统的做了一份学习系统的资料和视频,大概就下面这些,我就不全部写出来了,不然太长了影响大家的阅读。

330页PDF Android学习核心笔记(内含上面8大板块)

Android学习的系统对应视频

总结

我希望通过我自己的学习方法来帮助大家去提升技术:

  • 1、多看书、看源码和做项目,平时多种总结

  • 2、不能停留在一些基本api的使用上,应该往更深层次的方向去研究,比如activity、view的内部运行机制,比如Android内存优化,比如aidl,比如JNI等,并不仅仅停留在会用,而要通过阅读源码,理解其实现原理

  • 3、同时对架构是有一定要求的,架构是抽象的,但是设计模式是具体的,所以一定要加强下设计模式的学习

  • 4、android的方向也很多,高级UI,移动架构师,数据结构与算法和音视频FFMpeg解码,如果你对其中一项比较感兴趣,就大胆的进阶吧!

希望大家多多点赞,转发,评论加关注,你们的支持就是我继续下去的动力!加油!
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
的,架构是抽象的,但是设计模式是具体的,所以一定要加强下设计模式的学习

  • 4、android的方向也很多,高级UI,移动架构师,数据结构与算法和音视频FFMpeg解码,如果你对其中一项比较感兴趣,就大胆的进阶吧!

希望大家多多点赞,转发,评论加关注,你们的支持就是我继续下去的动力!加油!
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值