android IPC通信小结
来源:互联网 发布:重庆时时彩开奖软件 编辑:程序博客网 时间:2024/05/01 02:29
通信方式介绍
Bundle
文件共享
AIDL
Messenger
ContentProvider
Socket
Bundle
适合单向数据传输,即进程A启动进程B的服务或者其他组件时,通过intent.putExtra传输。
当服务端是service时,可以在对应的onStartCommand和onBind 方法中访问传输过来的intent,不过要注意,此intent是新的实例,不是原来的实例。
文件共享
通过序列化读写文件的方式,共享数据,注意android系统中读写是没有限制,所以文件读写需要有一定间隔,且不能处理并发读写。
主要使用类为ObjectOutputStream和ObjectInputStream:
/* * @author 龙龟的文具盒 *///写入操作File file = new FIle(fileUrl);if(!file.exists()){ try { //创建新的文件 file.createNewFile(); } catch (IOException e) { e.printStackTrace(); }}try { ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file)); //需要实现Serilizable接口,使数据序列化 //【实现Parcelable接口不行】 MyData myData = new MyData(); out.writeObject(myData); out.close();} catch (IOException e) { e.printStackTrace();}//读取//使用ObjectInputStream读取,跟写入对称...
流数据读写如果遇到非基本数据类型,则需要序列化,序列化主要有两种方式:
实现Serilizable接口
1. 简单方便,不需要实现其他方法
2. 由java提供,底层靠反射实现
3. I/O操作比较频繁
4. 适用于存储设备和网络传输
5. 具有serialVersionUID唯一标识值,决定写入的文件的序列化版本信息,自己设定可以防止程序随自己修改bean类而影响对旧版本bean文件流的反序列化
注意点:
1. 静态成员变量属于类而不是对象
2. transient标记的成员变量不参与序列化过程
3. 无法在bundle中传输
实现Parcelable接口
1. 实现起来较复杂
2. android自带,优化速度
3. 速度快
4. 适用于内存序列化,即用于bundle传输过程中最合适
5. 无法在IO操作中使用
注意:
List和Map序列化的前提是元素都是可序列化
/** * 类说明:实现Parcelable的类 * 创建人:龙龟的文具盒 */public class MyData implements Parcelable { public MyData(){} //构件反序列化的构造函数 protected MyData(Parcel in) { myDataBean = in.readParcelable(MyDataBean.class.getClassLoader()); name = in.readString(); id = in.readInt(); } public static final Creator<MyData> CREATOR = new Creator<MyData>() { @Override public MyData createFromParcel(Parcel in) { return new MyData(in); } @Override public MyData[] newArray(int size) { return new MyData[size]; } }; public MyDataBean getMyDataBean() { return myDataBean; } public void setMyDataBean(MyDataBean myDataBean) { this.myDataBean = myDataBean; } private MyDataBean myDataBean; public String getName() { return name; } public void setName(String name) { this.name = name; } private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } private int id; //若有文件描述符则需要返回1 @Override public int describeContents() { return 0; } //序列化过程 @Override public void writeToParcel(Parcel dest, int flags) { dest.writeParcelable(myDataBean, flags); dest.writeString(name); dest.writeInt(id); }}
AIDL
适用于多客户端对同一个服务端的并发访问情景。
实现过程:
1. 创建.aidl文件,客户端和服务端的路径必须一致
2. 定义aidl文件内接口,出现非支持类型则必须导包
3. build project后,系统会自动创建相应的interface
4. 在服务端service中实例化自动创建的interface中的Stub类,并且需要实现aidl中定义的接口
5. 通过onBind, 返回步骤四实例化的binder【非主线程】
6. 客户端通过实例化ServiceConnection【UI主线程】并实现onServiceConnected来获取服务端的binder对象,并调用 yourInterface.Stub.asInterface来获得相应的接口,并在适当的时候回调服务端方法【注意回调时尽量避免在UI线程回调】
AIDL支持的类型:
1. 原子类型(int,long,char,boolean)
2. String or CharSequence
3. List (实际为ArrayList) Map(实际为HashMap) 元素也必须是可支持的
【因为一般是服务端一对多,ArrayList并不支持并发读写,List的话选择CopyOnWriteArrayList最合适,但客户端只能收到ArrayList=。=】
4. 实现Parcelable接口的对象
自定义类型
自己实现的Parcelable,除了要有实现bean.java对象外,还需要在当前包下新建bean.aidl文件,并在里面定义parcelable对象。再需要引用该自定义类型的interface定义中,也需要import这个对象【注意的是,interface.aidl导入的,其实是从bean.aidl中导入的,不是从bean.java里】
而且注意对象前需要用 in, out 或者 inout修饰,这是由底层去实现的
in:输入型参数
out:输出型参数
inout:输入输出型参数
原子类型也是默认使用in
订阅者模式
实现方式:
1. 为客户端创建可以让服务端回调的aidl接口
2. 在服务器端的回调接口添加register和unregister方法,在service中实现时,采用数组来存储客户端listener
【数组应选用RemoteCallbackList,其保存真正的远程listener,实现靠ArrayMap,key:IBinder,value:Callback, 遍历能够找到真正的listener实例,能够真正unRegister,因为底层的IBinder是一致的。使用时必须和 beginBroadcast()与finishBroadcast()相匹配】
3. 服务端工作线程可以遍历list中的listener,而直接调用客户端的方法
4. 客户端listener方法中,通过handle交由UI线程处理
权限认证
1. 同一工程中的服务端和客户端可用onBind
2. 跨工程的服务端和客户端在服务端onTransact中验证
/* * @author 龙龟的文具盒 */ @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { //验证权限,客户端需要在androidmainfest中添加该权限 int check = checkCallingOrSelfPermission("PERMISSION"); if(check == PackageManager.PERMISSION_DENIED){ return false; } //验证包名 String packageName = null; String[] packages = getPackageManager().getPackagesForUid(getCallingUid()); if(packages!=null && packages.length>0) { packageName = packages[0]; } //匹配包名前缀 if(!packageName.startsWith("com.xxxx")){ return false; } return super.onTransact(code, data, reply, flags); }
断开重连
1. onServiceDisconnected中重连,UI线程
2. 给客户端Binder设置DeathRecipient监听,非UI线程
ps: 调试时虽然通过killProcess结束了服务端进程,但即使不自己重连,也会自动重连,这还是个梗orz待解决
//在onServiceConnected中注册mInterface.asBinder().linkToDeath(mBinderDeathRecipient,0);//实例化时,实现binderDied方法,并注意调用unlinkToDeath,异步重连也需要转化成同步请求bindService..
Messenger
简单化的aidl,客户端与服务端为一对一关系咯。
操作方式:
1. 服务端onBind中实例一个Messenger,和其依赖的handle,在handle中处理客户端的信息,onBind中返回messenger.getBinder
2. 客户端在onServiceConnected中将自己的Messenger作为replyTo参数放到Message中,再通过new Messenger(IBinder) 的send,把客户端数据传送到服务端
注意:
message的参数object在2.2之前不支持跨进程通信,2.2之后只有系统实现的Parcelable接口的对象才能传输,所以可以用bundle进行数据传输
ContentProvider
与sqlite结合使用,设置contentProvide的process属性,其就属于其他进程的
Socket
服务器端开工作线程,监听socket请求=。=
- android IPC通信小结
- Android ipc通信机制
- Android IPC通信
- android ipc通信机制
- Android IPC 通信 (二)
- android IPC 之Binder通信
- android-IPC进程间通信
- android IPC通信机制梳理
- android IPC进程间通信
- Android IPC 进程间通信
- Android IPC 通信 (二)
- Android跨进程通信IPC
- android IPC通信方式简述
- Android IPC 进程间通信
- Android IPC 进程间通信
- Android Messenger实现IPC通信
- Android IPC通信之Socket
- Android进程间通信IPC
- hdu5635 BestCoder Round #74 (div.2) LCP Array
- 二叉树转变为双向链表
- SQL优化,处理百万级以上的数据处理
- cocos 项目 接入友盟 android 推送sdk
- 我是如何给实验室的服务器上网的
- android IPC通信小结
- Linux内核分析之时间片轮转调度
- FZU ACM 题目分类(转自某位大神的博客)
- 用Category给类中添加属性
- 如何让代码封装性强,耦合度低(持续更新)
- Android系统-开篇
- 如何使用公众号接口来接收消息?
- 为什么要格外努力
- 第二天完整笔记