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跨进程通讯详解与实现,看一遍就懂的主要内容,如果未能解决你的问题,请参考以下文章