Android AIDL

Binder

        Binder是什么?

机制: Binder 是一种进程间通信的机制
驱动: Binder 是一个虚拟物理设备驱动
应用层: Binder 是一个能发起进程间通信的 JAVA
Binder 就是 Android 中的血管,在 Android 中我们使用 Activity,Service 等组件都需要和 AMS
system_server )进行通信,这种跨进程的通信都是通过 Binder 完成。
Activity,Service 等组件和 AMS 不是同一个进程,其实也是多进程通信。

Android系统中,涉及到多进程间的通信底层都是依赖于Binder IPC机制。

例如当进程 A 中的 Activity 要向进程 B 中的 Service 通信,这便需要依赖于 Binder IPC 。不仅于此,整
Android 系统架构中,大量采用了 Binder 机制作为 IPC (进程间通信, Interprocess
Communication )方案。
也存在部分其他的 IPC 方式,如管道、 SystemV Socket

        为什么使用Binder

性能方面:
Binder 相对于传统的 Socket 方式,更加高效
Binder 数据拷贝只需要一次,而管道、消息队列、 Socket 都需要 2 次,共享内存方式一次内存拷贝
都不需要,但实现方式又比较复杂。
安全方面:
传统的进程通信方式对于通信双方的身份并没有做出严格的验证,比如 Socket 通信的 IP 地址是客户
端手动填入,很容易进行伪造
Binder 机制从协议本身就支持对通信双方做身份校检,从而大大提升了安全性
IPC 原理
Android AIDL_第1张图片
Binder IPC 实现原理
跨进程通信是需要内核空间做支持的。传统的 IPC 机制如管道、 Socket 都是内核的一部分。
Binder IPC 正是基于内存映射( mmap )来实现的,但是 mmap() 通常是用在有物理介质的文件系统
上,进程中的用户区域是不能直接和物理设备打交道的。
如果想要把磁盘上的数据读取到进程的用户区域,需要两次拷贝(磁盘 –> 内核空间 –> 用户空间) , 通常在
这种场景下 mmap() 就能发挥作用,通过在物理介质和用户空间之间建立映射,减少数据的拷贝次数,
用内存读写取代 I/O 读写,提高文件读取效。

AIDL

 AIDL简介

        AIDL( Android 接口定义语言),可以使用它定义客户端与服务端进程间通信( IPC )的编程接口。在 Android系统中,每个进程都运行在一块独立的内存中,在其中完成自己的各项活动,与其他进程都分 隔开来。可是有时候我们又有应用间进行互动的需求,比较传递数据或者任务委托等,AIDL 就是为了满 足这种需求而诞生的。通过AIDL ,可以在一个进程中获取另一个进程的数据和调用其暴露出来的方法, 从而满足进程间通信的需求。 AIDL是用于定义服务端和客户端通信接口的一种描述语言,可以拿来生产 IPC 代码,从某种意义上说 AIDL其实就是一个模板,因为在使用过程中,实际起作用的并不是 AIDL 文件,而是据此生产的一个 Interface的实例代码, AIDL 其实是为了避免我们重复写代码而出现的一个模板。
注意: 只有在需要不同应用的客户端通过 IPC 方式访问服务,并且希望在服务中进行多线程处理
时,您才有必要使用 AIDL 。如果您无需跨不同应用执行并发 IPC ,则应通过实现 Binder 来创建接
口;或者,如果您想执行 IPC ,但 需要处理多线程,请使用 Messenger 来实现接口。无论如
何,在实现 AIDL 之前,请您务必理解绑定服务。
  使用流程
        1. 在 .aidl 文件中定义 AIDL 接口,并将其添加到应用工程的 src 目录下,创建完成之后 rebuild
        2. Android SDK 工具会自动生成基于该 .aidl 文件的 IBinder 接口,具体的业务对象实现这个接口, 这个具体的业务对象也是 IBinder 对象,当绑定服务的时候会根据实际情况返回具体的通信对象 (本地还是代理)
        3. 将客户端绑定到该服务上,之后就可以调用 IBinder 中的方法来进行进程间通信( IPC
下面从几个方面介绍 AIDL 的使用
        1. 创建 .aildl 文件
        2. 具体的业务对象实现基于 .aidl 文件生成的接口
        3. 向客户端公开接口
        4. 客户端远程调用 5. 验证 AIDL
  创建 .aildl 文件
        在 AIDL 中可以通过可带参数以及返回值的一个或多个方法来声明接口,参数和返回值可以是任意类 型,AIDL 中支持的数据类型如下: java 的 8 种数据类型: byte short int long float double boolean char
        除此之外支持 String charSequence List Map
        自定义数据类型
        如果参数或返回值类型为 List Map 时:
List 中的所有元素都必须是 AIDL 支持的数据类型、其他 AIDL 生成的接口或自己声明的可打包类
型。可选择将 List 用作 通用 类(例如, List )。另一端实际接收的具体类始终是 ArrayList ,但生
成的方法使用的是 List 接口。
Map 中的所有元素都必须是 AIDL 支持的数据类型、其他 AIDL 生成的接口或您声明的可打包类
型。 不支持通用 Map (如 Map 形式的 Map )。 另一端实际接收的具体类始终
HashMap ,但生成的方法使用的是 Map 接口。
具体的业务对象实现基于 .aidl 文件生成的接口
        打开IPersonAidlInterface.aidl ,在 .aidl 文件中添加具体的业务方法,文件内容如下 :
interface IkeyAidlInterface {
    void setName(String name);
        void setAge(int money);
        String getInfo();
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
}
. 然后,重新 rebuild project , Android SDK 工具会在相应的目录生成对应的与 .aidl 文件同名的 .java
接口文件,具体目录如下:
Android AIDL_第2张图片

  那么这个业务要体现在什么地方呢,从上面可知 Stub 是一个抽象类,那么它所提供的具体业务必
然需要一个具体的实现类来完成,下面实现这个具体的业务类,具体如下

 


    public class IKeyimpl extends IkeyAidlInterface.Stub{
        String name;
        int money;
        @Override
        public void setName(String name) throws RemoteException {
            this.name=name;
        }

        @Override
        public void setAge(int money) throws RemoteException {
            Intent intent = new Intent();
            intent.setClass(KeyService.this,MainActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
            this.money=money;
        }

        @Override
        public String getInfo() throws RemoteException {
            return "交易账户:"+name+"金额是:"+money;
        }

        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }
    }

向客户端公开接口

创建一个 Service 以便对外提供具体的业务,具体如下:
public class KeyService extends Service {
    public KeyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return new IKeyimpl();
    }
}

也可以将Stub 抽象类与service复合写如下:

public class KeyService extends Service {
    public KeyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return new IKeyimpl();
    }


    public class IKeyimpl extends IkeyAidlInterface.Stub{
        String name;
        int money;
        @Override
        public void setName(String name) throws RemoteException {
            this.name=name;
        }

        @Override
        public void setAge(int money) throws RemoteException {
            Intent intent = new Intent();
            intent.setClass(KeyService.this,MainActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
            this.money=money;
        }

        @Override
        public String getInfo() throws RemoteException {
            return "交易账户:"+name+"金额是:"+money;
        }

        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }
    }
}

客户端远程调用

通过上面几步完成了服务的搭建,并将服务运行在独立进程中,下面主要就是客户端的具体调用了,具 体实现参考如下:
public class MainActivity extends AppCompatActivity {
    private Button button,button2,button3,button4;
    TextInputEditText textField,edt_one;
    private IkeyAidlInterface ikeyAidlInterface;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button=findViewById(R.id.button);
        button2=findViewById(R.id.button2);
        button3=findViewById(R.id.button3);
        button4=findViewById(R.id.button4);
        textField=findViewById(R.id.textField);
        edt_one=findViewById(R.id.edt_one);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent();
                intent.setComponent(new ComponentName("com.example.day36start2","com.example.day36start2.KeyService"));
                bindService(intent,conn,BIND_AUTO_CREATE);

            }
        });
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                try {
                    ikeyAidlInterface.setName("a123456");
                    ikeyAidlInterface.setAge(100);
                    String zys=ikeyAidlInterface.getInfo();
                    Log.i("take", zys);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
        button3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

            }
        });

    }
    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            ikeyAidlInterface = IkeyAidlInterface.Stub.asInterface(service);
            Log.i("TAG" , ""+ikeyAidlInterface);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    };
}

在新版本要在AndroidManifest.xml中写上如下代码:


        
    

你可能感兴趣的:(android,android,studio,java)