Android Binder,AIDL跨进程通讯详解与实现,看一遍就懂

Posted 奔跑的蜗牛、Z

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Binder,AIDL跨进程通讯详解与实现,看一遍就懂相关的知识,希望对你有一定的参考价值。

1.说到AIDL,就会联想到Binder机制,

                Binder 是一种进程间通信机制
                整个app属于客户端,系统是服务端,他们之间的通讯就是通过IPC交互,中间服务就是serviceSystem
        优点:性能,稳定性,安全性
        设计:Client/Server/ServiceManager/驱动
        实现:AIDL   

二、核心代码处

1.可以通过AndroidStudio创建:

 1.1选中一个包进行新建一个aidl,系统会自动生成一个aidl的文件夹

 1.2手动创建文件夹,创建包名,然后在包内创建aidl文件。

1.3我们创建两个AIDL文件 IMsgManager.aidl,IReceiverMsgListener

 IMsgManager:消息管理类,提供消息的接口

IReceiverMsgListener:消息接收类,做转发使用

1.4Msg是对象,aidl常见的参数只支持简单的数据类型,对象需要通过Parcelable序列化处理

        1.4.1 先定义一个Msg 实现 Parcelable接口,,注意这个类的包名一定要与aidl文件下的包名一致,因为我们要定义一个空的Msg.aidl文件,这样Msg.aidl文件才会与Msg.Java文件关联起来

Msg.aidl文件:删除interface Msg,将Msg申明为 parcelable;

这样就就可以了。

 IMsgManager:

 由于aidl文件不能关联,使用类都需要手动导入包名。

IReceiveMsgListener:

定义好AIDL文件,我们要生成对应的java文件:点击

将项目编译一下,aidl文件对应的java文件出现在这个下方。

这个时候有人会发现少了一个Msg的java文件,由于我们将Msg.aidl申明为 parcelable,将会关联Parcelable的实体,和java文件已关联起来。

这样,我们就可以通过aidl发送自定义对象。

2.Service的处理(C/S)

        2.1我们需要创建一个Service ,作为服务端在监控

public class MySevice extends Service 
    //AIDL不支持正常的接口回调,使用RemoteCallbackList实现接口回调
    private RemoteCallbackList<IReceiveMsgListener> mReceiveListener = new RemoteCallbackList<IReceiveMsgListener>();


    @Nullable
    @Override
    public IBinder onBind(Intent intent) 
        return new MyIBinder();
    



    public class MyIBinder extends IMsgManager.Stub 

        @Override
        public void sendMsg(Msg msg) throws RemoteException 
            receiveMsg(msg);
        

        @Override
        public void registerReceiveListener(IReceiveMsgListener receiveListener) throws RemoteException 
            mReceiveListener.register(receiveListener);
        

        @Override
        public void unregisterReceiveListener(IReceiveMsgListener receiveListener) throws RemoteException 
            boolean success = mReceiveListener.unregister(receiveListener);
            if (success)
                Log.d("tag","===  解除注册成功");
            else 
                Log.d("tag","===  解除注册失败 ");
            

        

        @Override
        public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException 
            return super.onTransact(code, data, reply, flags);
        
    ;

    //收到消息处理
    public void receiveMsg(Msg msg) 
        //通知Callback循环开始,返回size为实现mReceiveListener回调的个数
        final int size = mReceiveListener.beginBroadcast();
        msg.setMsg("我是服务器,我收到了:"+msg.getMsg());
        for (int i = 0; i < size; i++)
            IReceiveMsgListener listener = mReceiveListener.getBroadcastItem(i);
            if (listener != null)
                try 
                    listener.onReceive(msg);
                 catch (RemoteException e) 
                    e.printStackTrace();
                
            
        
        //通知通知Callback循环结束
        mReceiveListener.finishBroadcast();
    



2.2将service注册到androidManifest

<service
    android:name="com.example.mydemo.service.MySevice"
    android:process=":remote"//同一应用内跨进程通信需
    android:enabled="true"
    android:exported="true" //暴露
    >

    <intent-filter>
        <action android:name="com.test.aidl.action"/>
    </intent-filter>

</service>

三、Service与Activity之间的通讯(在当前APP内)

        3.1绑定服务

IMsgManager myIBinder = null;
private TextView textView;
private Button button_1, button_2, button_3;
public static final String ACTIO_SERVICE = "com.test.aidl.action";
IMsgManager iMsgManager;
private EditText  editText_1;

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



private void initView() 
    editText_1=findViewById(R.id.edit_1);
    textView = findViewById(R.id.text_1);
    button_1 = findViewById(R.id.btn_1);
    button_2 = findViewById(R.id.btn_2);
    button_3 = findViewById(R.id.btn_3);

    button_1.setOnClickListener(this);
    button_2.setOnClickListener(this);
    button_3.setOnClickListener(this);




@Override
public void onClick(View v) 

    if (v == button_1) 
        //绑定
        bindService();

     else if (v == button_2) 
        //发送
        try 
            if (myIBinder != null) 
                if (editText_1.getText().toString().isEmpty())
                    return;
                Msg msg = new Msg("服务端发送:"+editText_1.getText());
                myIBinder.sendMsg(msg);
            
         catch (RemoteException e) 
            e.printStackTrace();
        

     else if (v == button_3) 
        //解绑
        unbindService(connection);

    




private void bindService() 
        //注册service
    Intent intent = new Intent(this, MySevice.class);
    intent.setAction(ACTIO_SERVICE);
    bindService(intent, connection, Service.BIND_AUTO_CREATE);




//service的链接
private ServiceConnection connection = new ServiceConnection() 
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) 
        myIBinder = IMsgManager.Stub.asInterface(service);
        iMsgManager = IMsgManager.Stub.asInterface(service);
        try 
            //注册binder连接
            iMsgManager.asBinder().linkToDeath(mDeathRecipient, 0);
         catch (RemoteException e) 
            e.printStackTrace();
        

        try 
            iMsgManager.registerReceiveListener(mReceiveMsgListener);
         catch (RemoteException e) 
            e.printStackTrace();
        

    

    @Override
    public void onServiceDisconnected(ComponentName name) 
        //断开连接

    
;




private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() 
    // //当承载IBinder的进程消失时接收回调的接口
    @Override
    public void binderDied() 
        if (null == iMsgManager) 
            return;
        
        //解绑
        iMsgManager.asBinder().unlinkToDeath(mDeathRecipient, 0);
        iMsgManager = null;
    
;

private IReceiveMsgListener mReceiveMsgListener = new IReceiveMsgListener.Stub() 

    @Override
    public void onReceive(Msg msg) throws RemoteException 
             //消息分发
        textView.append("\\n" + msg.getMsg());


    
;

 这样就完成再App的消息分发

四、我们要在两个App中实现消息传递,也就是跨进程IPC。

由于我们已完成了一个service端的开发,我们在创建一个新的app,作为令一个进程。

4.1同样把所service APP中的aidl复制到B的app中,Msg对象也要一同复制到对应的包下(两边保持一致)

把Msg自定义的实体也复制过来。两边要保持包名一致。接下我们还是需要make一下项目。

执行完,会生成一下

4.2  实现service的绑定,可以把A app的代码复制过来。修改注册service方法

IMsgManager myIBinder = null;
private TextView textView;
private Button button_1, button_2, button_3;
public static final String ACTIO_SERVICE = "com.test.aidl.action";
IMsgManager iMsgManager;
EditText edit_1;

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



private void initView() 
    edit_1=findViewById(R.id.edit_1);
    textView = findViewById(R.id.text_1);
    button_1 = findViewById(R.id.btn_1);
    button_2 = findViewById(R.id.btn_2);
    button_3 = findViewById(R.id.btn_3);

    button_1.setOnClickListener(this);
    button_2.setOnClickListener(this);
    button_3.setOnClickListener(this);




@Override
public void onClick(View v) 

    if (v == button_1) 
        //绑定
        bindService();

     else if (v == button_2) 
        //接收
        try 
            if (myIBinder != null) 
                if (edit_1.getText().toString().isEmpty())
                    return;
                Msg msg = new Msg("客户端发送:"+edit_1.getText());
                myIBinder.sendMsg(msg);
            
         catch (RemoteException e) 
            e.printStackTrace();
        

     else if (v == button_3) 
        //解绑
        unbindService(connection);

    




private void bindService() 
//绑定需要注意一下,由于我们启动其他应用的,需要知道包名和,filter-action
    Intent intent = new Intent();
    intent.setPackage("com.example.mydemoa");//包名,服务端的包名(service)
    intent.setAction(ACTIO_SERVICE);//action
    bindService(intent, connection, Service.BIND_AUTO_CREATE);




private ServiceConnection connection = new ServiceConnection() 
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) 
        myIBinder = IMsgManager.Stub.asInterface(service);
        iMsgManager = IMsgManager.Stub.asInterface(service);
        try 
            iMsgManager.asBinder().linkToDeath(mDeathRecipient, 0);
         catch (RemoteException e) 
            e.printStackTrace();
        

        try 
            iMsgManager.registerReceiveListener(mReceiveMsgListener);
         catch (RemoteException e) 
            e.printStackTrace();
        

    

    @Override
    public void onServiceDisconnected(ComponentName name) 

    
;


private void showUI() throws RemoteException 




private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() 
    // //当承载IBinder的进程消失时接收回调的接口
    @Override
    public void binderDied() 
        if (null == iMsgManager) 
            return;
        
        iMsgManager.asBinder().unlinkToDeath(mDeathRecipient, 0);
        iMsgManager = null;
    
;

private IReceiveMsgListener mReceiveMsgListener = new IReceiveMsgListener.Stub() 

    @Override
    public void onReceive(Msg msg) throws RemoteException 
        msg.setTime(System.currentTimeMillis());
        textView.append("\\n" + msg.getMsg());


    
;

4.4这样基本完成,接下来开始测试。测试先启动service的app。然后在打开b的,否则B打开,service没有启动,导致消息无法传递

五、结果:

这样就完成了跨进程消息传递 

注意:关于自定义对象,是先创建一个实体对象,实现Parcelable接口,再在aidl文件夹下的包内创建一个aidl文件名为java一样的。同事包名也一样,删除aidl文件内接口代码行,

interface Msg
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */

然后改成申明为:parcelable Msg;即可。不然会报错。网上大多数教程都没有交会如何关联自定义java文件与aidl文件。

        

*************************************************************************************************************

很感谢官方,今天刚整理好,就推上了领域内容热榜第八名。以后将会写出更好的博客回馈大家。

 

以上是关于Android Binder,AIDL跨进程通讯详解与实现,看一遍就懂的主要内容,如果未能解决你的问题,请参考以下文章

Android IPC机制:浅谈Binder的使用

Android Studio创建AIDL文件并实现进程间通讯

Android进阶笔记:AIDL内部实现详解

Android跨进程通信Binder机制与AIDL实例

Android跨进程通信Binder机制与AIDL实例

Binder的使用(跨进程——AIDL,非跨进程)