IPC通讯 内部进程通信
2016-06-07 14:41
295 查看
IPC:进程间通讯、跨进程通信
android中的IPC方式
1.bundle2.使用文件共享,两个进程通过读/写同一个文件完成数据的共享,使用对象流序列化到文件中,反序列化出来。
3.使用Messenger,通过它可以实现不同
4.使用AIDL方式
1.Messenger 实现IPC
原理:进程间通过messenge(信使)完成数据的传输。底层是采用AIDL实现/binder实现。
建立两端 站 ,由信使携带 message 信息 进行传输。
1.客户端和服务端的通讯
Messenger 和 Message 都实现了Parcelable接口,都可以跨进程通信
通过Messenger 发送的Message对象,只能支持的载体是 what ,arg1,arg2,Bundle和replyTo .
服务端: Messenger mMessenger = new Messenger(new ServerHander()); public static ServerHander extends Handler{ public void handlerMessage(Message msg){ switch(msg.what){ case 0: `Log.i("messenger","client send to server :"+ msg.getData().getString("key").toString()); //Contants.FROM_SERVER 是msg.what,用来判断客户段接受的handler.msg.what . Message ms = Message.obtai(null,Contants.FROM_SERVER); Bundle data = new Bundle(); data.putString("key","server send to message : ;;;"); ms.setData(data); try { msg.replyTo.send(ms); } catch (RemoteException e) { // TODO Auto-generated catch block e.printStackTrace(); } ` break; } } } 客户端: `public Messenger msger = new Messenger(new MessengerHandler()); public class MessengerHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case Contant.FROM_SERVER: Toast.makeText(MainActivity.this, msg.getData().get("key").toString(), 0).show(); break; } super.handleMessage(msg); } } @Override public void onClick(View v) { // TODO Auto-generated method stub // try { // int add = binder.add(new Data(10, 20)); // btn.setText(add + ""); // // } catch (RemoteException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } // messenger ipc method Message msg = Message.obtain(null, Contant.FROM_CLIENT); Bundle data = new Bundle(); data.putString("key", "client send 的信息"); msg.setData(data); //服务段要发送给客户端则需要将客户端的messenger传给服务端。 !!!!!!!! msg.replyTo =msger; try { mMessenger.send(msg); } catch (RemoteException e) { // TODO Auto-generated catch block e.printStackTrace(); }
CopyOnWriteArrayList 支持并发读/写,不是ArrayList
ConCurrentHashMap
binder 机制
在服务端可能由于某些原因导致异常终止,这个时候我们到服务端的Binder连接断裂,我们称之为 Binder死亡,
会导致我们的远程调用失效。这时我们需要重新连接 服务。
有两种方法:
1.geibinder设置DeathRecipient监听,当Binder死亡时,我们会收到binderDied方法的回调。在binderDied方法中我们可以重连远程服务,
2在onServiceDisconnected中重连远程服务。
区别:
onServiceDisconnected在ui线程被回调,而binderDied在binder线程池中回调。
也就是说 binderDied不能再主线程回调。
##实现客户端和服务端的观察者模式 - 当服务端的数据有新的内容的时候,通知客户端进行更新。 - 创建一个aidl接口,IOnNewDataReviceListener 定义一个onNewDataRevice - ( Data data) 方法 ,用来新数据添加到服务端时,实现通知客户端 - 在IDataManager.aidl中声明两个方法;registerListener - (IOnNewDataReviceListener listener)和unRegisterListener - (IOnNewDataReviceListener listener); -在service类中 定义 IDataManager.stub的子类,重写几个方法,onBind()返回该子类的实例。 - 客户端创建的时候,要将IOnNewDataReviceListener监听注册到服务器中。 - 退出时要解除注册。 - 服务端当有新数据时,会回调客户端的IOnNewDataReviceListener中的 - onNewDataRevice(Data data)方法。但是这个方法是在客户端的binder线程池 - 中运行的,因此,为了方便ui操作,我们将用一个Handler 可以切换到可以护 - 短的主线程进行操作。 - 进行客户端的解注册时,binder会将客户端传递过来的对象重新转换成一个 - 新对象。服务端接收到客户端的对象是新的一个对象,所以就不能解注册。 -RemoteCallbackList<E extends IInterface> 类 ,使系统专门用于跨进程删除 Listener的接口,支持管理任意的aidl接口 原理:内部是一个Map结构专门用来保存aidl接口,它的key是IBinder类型,value是Callback类型。 key的值:IBinder key = listener.asBinder(); value的值:Callback value = new Callback(listener,cookie); 多次跨进程传递对象在服务端生成一个不同的对象,但是这些新生成的对象有 一个共同点就是,他们使用的底层binder是同一个binder,所以当客户端解注 册的时候,只需要遍历服务端的所有的Listener,找到和解注册listener相同 binder的listener,移除掉就可以了,这就是remoteCallbackList为我们做的。 - 同时RemoteCallbackList还有一个很好用的功能,就是当客户端终止进程时, - 它能自动的移除客户端注册的listener,并且,它实现了多线程同步机制。我 - 们不需要进行额外的线程同步工作。 客户端调用远程服务端的方法时,,被调用的方法是在服务端的binder线程池 执行的,客户端的程序挂起,等待服务端的方法返回信息。如果服务端的方法 是一个比较耗时的操作,那么,客户端就会长时间的阻塞在这里,如果客户端 是主线程的话就会导致ANR,因为onServiceConnected 和 onServiceDisconnected 方法都是运行在主线程中的。 因为服务端本身就是运行在服务端的Binder线程池中,所以服务端的方法可以 执行大量的好事操作,这个时候.就要避免在服务端方法中开线程执行异步任 务,除非明确知道自己在干什么,否则不建议做。 ##Aidl的 给服务加上权限验证功能 权限验证失败无法调用服务的方法。 - 1 可以在onBind()中进行验证,验证不通过就返回null,这样验证失败客户端直接无法绑定服务。验证方式有多种,如。permission验证 - 1.先在 AndroidMenifest中声明所需的权限,如: > <permission >android:name = "com.mrk.myqqq.permission.ACCESS_MY_SERVICE" >android:protextionLevel = "normal" /> - 定义了之后就可以在我们的Service中的onBinde()方法中做权限验证。 >{ > >int check = checkCallingOrSelfPermission("com.mrk.myqqq.permission.ACCESS_MY_SERVICE""); >if(check == PackageManager.PERMISSION_DENIED){ > >.return null; > >} >return mBinder; } - 客户端只有在menifest文件中写入权限即可 ><uses-permission android : name = "com.mrk.myqqq.permission.ACCESS_MY_SERVICE"; - 2 可以在服务端的onTransact方法中进行权限验证,如果验证失败返回false;这样服务端就不会终止执行AIDL中的方法从而达到保护服务端的效果。 - 可以采用permission验证 - 采用Uid和Pid来做验证。 >通过getCallingUid()和getCallingPid()可以拿到客户端所属的Uid 和Pid,通过这两个参数我们可以做一些验证的工作 服务端获取包名。 > String name = null; > String[] packages = getPackageManager().getPackagesForUid(getCallingUid()); >if(package != null && packages.length>0){ >packageName = packages[0]; >} >if(!packageName.startsWith("com.mrk")){ >return false;} >return super.onTransact(code,data,reply,flags); >
ContentProvider
- 是android中提供的专门用于不同应用间进行数据共享的方式,从这一点来看,它 - 天生就是和进程间通信。和Messenger一样,contentProvider的底层实现同样也 - 是Binder,由此可见,Binder在Android系统中是何等的重要。
继承ContentProvider类实现6个抽象方法。
注册这个类,必须要声明android:authorities的标识,这是contentProvider的唯一标识.
相关文章推荐
- leetcode-database-178.Rank Scores
- 使用CoordinatorLayout实现ToolBar扩展与收缩
- (RHCA436)3 Quorum
- 递归删除List元素
- 从linphone_core_new_with_config研究linphone
- Linked List Cycle
- eclipse中clean操作中如何将validating除去
- Kafka+Storm+HDFS整合实践
- Android多线程研究(9)——线程锁Lock
- iOS数据持久化 归档 plist文件
- (RHCA436)2 集群基础管理/新节点添加
- jsp指令中的taglib指令
- 云智巡在连锁药店的巡检作用
- ChemDraw怎么绘制动物细胞结构
- (RHCA436)1 创建集群
- org.springframework.dao.DuplicateKeyException: 问题
- Java 4种单例
- 当我真正理解了扩展欧几里得定理
- C# 获取本机的串口号
- (RHCSA)7 LDAP+kerberos+autofs实现账户验证登录