IPC机制(一)
来源:互联网 发布:淘宝dota2齿樱价格 编辑:程序博客网 时间:2024/04/27 13:59
一、概念
IPC:inter-Process Communication,进程间通信或者跨进程通信。
例如:Bundle、文件共享、基于Binder的AIDL和Messenger、ContentProvider、Socket等
1、线程:CPU调度的最小单位
进程:一个执行单元,一般指一个程序或应用。一个进程可包含多个线程。
2、应用场景:
一个应用采用多线程,两个应用间通信。
3、开始多进程
(1)给四大组件在清单文件中指定Android:process属性,开启多进程。 默认进程的进程名是包名。 系统为每个应用分配一个唯一UID,UID相同的应用才能共享数据。 (拥有独立虚拟机,Application,内存空间)
(2)通过JNI在native层fork一个新的进程
通过adb shell ps | grep 包名 查看一个包名下所存在的进程信息
4、多进程的问题:
每个进程分配独立的虚拟机,不同虚拟机在内存分配上有不同地址空间,所以在访问同一个类对象产生多个副本。如果多进程之间通过内存同享数据会同享失败。
(1)静态成员和单例模式失效
(2)线程同步机制失效 (不在同一内存,无法锁住同一对象)
(3)SharedPreferences可靠性下降(sp不支持两个进程同时执行写操作)
(4)Application多次创建(同一进程、同一虚拟机、同一Application)
5、Android中的IPC方式:
(1)、使用Bundle :Activity、Service和Receive都支持Intent中传递Bundle数据,由于Bundle实现了Parcelable接口,可在不同进程中进行通信。
(2)、使用文件共享(但是两个线程同时操作可能会出问题,sharedPrefrences有缓存策略,读写不可靠)
(3)、使用Messenger : 不同进程中传递Message对象,底层实现是AIDL
(4)、使用AIDL:
(5)、使用ContentProvider: 不同应用中进行数据共享,底层实现是Binder
(6)、Socket:通过网络传输字实现实时通信
Messenger和AIDL区别:
Messenger以串行方式处理消息,如果有大量的并发请求,只能一个个处理,不适合使用Messenger。
AIDL可以跨进程调用方法,Messenger只能传递消息
二、序列化
序列化,表示将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络上进行传输,也可以存储到本地。
通过Intent和Binder传输数据时需要使用序列化(内存和内存之间传输的数据需要序列化以后的行式)
1、Serializable接口:序列化接口
声明一个serialVersionUID。在反序列过程中,会对两个UID进行对比,如果一致才可以进行反序列化。
如果不声明UID,在反序列时,当前类发生改变(增加或删除了变量),会反序列化失败。
注:静态成员变量属于类,不会对象,不会参与序列化。用transient关键字标记的变量不参与序列化。
原理:将一个对象转换成可存储可传输的状态。
2、Parcelable接口:实现这个接口,可以通过Intent和Binder进行传递。
实现Parceable接口,重写describeContents和writeToPracel()两个方法。还需要提供一个CREATOR的常量,重写createFromParcel()和newArray()两个方法。
原理: 将一个完整的对象进行分解,分解的每一个部分都是Intent所支持的数据类型。
在序列化过程中需要实现序列化、反序列化和内容描述
public class PicEntity implements Parcelable { public String picURL; public String middlePicURL; public String smallPicURL; //从序列化后得对象中创建原始对象 protected PicEntity(Parcel in) { picURL = in.readString(); middlePicURL = in.readString(); smallPicURL = in.readString(); } //反序列化的过程 public static final Creator<PicEntity> CREATOR = new Creator<PicEntity>() { //从序列化后的对象返回原始对象 @Override public PicEntity createFromParcel(Parcel in) { return new PicEntity(in); } //创建指定长度的原始对象数组 @Override public PicEntity[] newArray(int size) { return new PicEntity[size]; } }; //返回当前对象的内容描述 @Override public int describeContents() { return 0; } //序列化的过程 @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(picURL); dest.writeString(middlePicURL); dest.writeString(smallPicURL); }}Intent、Bundle、Bitmap都是直接序列化的。List和Map也可序列化,里面的每个元素都是可序列化的。
3、区别
Serializable 是Java序列化接口,将整个对象序列化,简单开销大,序列化和反序列化需要大量I/O操作。
Parcelable是Android序列化方式,适合Android平台。将对象的每个部分序列化,效率高,使用麻烦。
三、BinderBinder类,实现了IBinder接口。主要是AIDL(多线程,多并发访问)和Messenger(底层还是AIDL,单线程处理)
作用:跨进程通信的一种方式
(1)客户端和服务端进行通信的媒介,bindService时,服务端返回一个Binder对象,客户端客户获取数据。
(2)ServiceManager连接 各种Manager(ActivityManager、WindowManager等)和对应ManagerService的桥梁。
四、Messenger
信使,可以在不同的进程中传递Message对象,在Message中放入要传递的数据
特点:对AIDL做了封装,一次只能处理一个请求。
流程图:
使用步骤:
1、服务端
public class MessengerService extends Service { private static String TAG = "MessengerService"; private Messenger messenger = new Messenger(new MessageHandler()); @Override public void onCreate() { super.onCreate(); } @Nullable @Override public IBinder onBind(Intent intent) { //返回这个messenger对象底层的Binder return messenger.getBinder(); } //处理服务端发送来的数据 private static class MessageHandler extends Handler{ @Override public void handleMessage(Message msg) { String myText = msg.getData().getString("msg"); LogUtil.i(TAG,"收到的消息:"+myText); //回复消息 Messenger client = msg.replyTo; Message replyMessage = Message.obtain(null,2); Bundle bundle = new Bundle(); bundle.putString("reply","收到了消息了啊"); replyMessage.setData(bundle); try { //做出回复 client.send(replyMessage); }catch (RemoteException e){ e.printStackTrace(); } } }}清单文件配置:
<service android:name=".service.MessengerService" android:process=":remote" ></service>2、客户端
/** * * 用户端 */public class MainActivity extends BaseActivity{ private Messenger messenger; @Override protected int getContentViewID() { return R.layout.activity_main; } @Override public void initView() { super.initView(); Intent intent = new Intent(this, MessengerService.class); bindService(intent,connection,BIND_AUTO_CREATE); } private Messenger replyMessenger = new Messenger(new MessageHandler()); private static class MessageHandler extends Handler { @Override public void handleMessage(Message msg) { String myText = msg.getData().getString("reply"); LogUtil.i(TAG,"客户端收到的消息:"+myText); } } private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { //绑定成功后,用服务端返回的IBinder来创建一个Messenger //通过这个Messenger向服务端发消息 messenger = new Messenger(service); Message message = Message.obtain(null,1); Bundle bundle = new Bundle(); bundle.putString("msg","ssssss"); message.setData(bundle); //客户端接收到服务端回复的消息 message.replyTo = replyMessenger; try { //发送消息 messenger.send(message); }catch (RemoteException e){ e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { LogUtil.i("链接断开"); } }; @Override protected void onDestroy() { super.onDestroy(); unbindService(connection); }}五、AIDL:
1、创建实体类,实现Parcelable
创建一个AIDL文件,将需要给客户端调用的接口在AIDL文件中声明
public class Book implements Parcelable { public int bookId; public String bookName; public Book(int bookId,String bookName){ this.bookId=bookId; this.bookName = bookName; } protected Book(Parcel in) { bookId = in.readInt(); bookName = in.readString(); } @Override public String toString() { return "["+bookId+"---"+bookName+"]"; } public static final Creator<Book> CREATOR = new Creator<Book>() { @Override public Book createFromParcel(Parcel in) { return new Book(in); } @Override public Book[] newArray(int size) { return new Book[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(bookName); dest.writeInt(bookId); }}
2、AIDL接口的实现:
(1)AIDL文件支持的数据类型
基本数据类型(int、long、char、boolean、double等)
String和CharSequence
ArrayList : 里面的元素必须能被AIDL支持
HashMap
Parcelable:实现了Parcelable接口的对象
注:其中Parcelable对象和AIDL对象显式import进来
创建一个AIDL文件,将需要给客户端调用的接口在AIDL文件中声明
// IBookManager.aidlpackage com.example.hejian.demo2.aidl;//导入所需要使用的非默认支持数据类型的包import com.example.hejian.demo2.aidl.Book;interface IBookManager{List<Book> getBookList();void add(in Book book);}
(2)如果有自定义Parcelable对象,必须建一个同名的AIDL文件
// Book.aidl//这个文件的作用是引入了一个序列化对象 Book 供其他的AIDL文件使用//注意:Book.aidl与Book.java的包名应当是一样的package com.example.hejian.demo2.aidl;parcelable Book;
3、服务端
创建一个Service,在Service中实现这个AIDL接口。
注:AIDL方法是在服务端的Binder线程池中执行,可能出现并发访问的情况(可使用CopyOnWriteArrayList进行并发访问)
4、绑定服务端的Service,通过服务器返回的Binder对象转成AIDL接口所需类型。5、专门删除跨进程的listener的接口RemoteCallbackList。客户端进程终止,自动移除客户端注册的listener
原理:内部有一个map专门保存所有的AIDL回调,map的key时IBinder类型,value是Callback类型(真正的远程listener)
他们底层的Binder对象是同一个,将相同的key的listener删除掉就可。
// IOnNewBookArrivedListener.aidlpackage com.example.hejian.aidldemo;// Declare any non-default types here with import statementsimport com.example.hejian.aidldemo.Book;//新书到了的监听interface IOnNewBookArrivedListener { void onNewBookArrived(in Book newBook);}服务端Service:
/** * 服务端 */public class AIDLService extends Service { private CopyOnWriteArrayList<Book> mBooks = new CopyOnWriteArrayList<>(); public final String TAG = this.getClass().getSimpleName(); private RemoteCallbackList<IOnNewBookArrivedListener> backListener = new RemoteCallbackList<>(); @Override public void onCreate() { super.onCreate(); mBooks.add(new Book(13,"思维")); mBooks.add(new Book(23,"思维1")); } private Binder binder= new IBookManager.Stub(){ @Override public List<Book> getBookList() throws RemoteException { Log.e(TAG, "获取到服务端list : " + mBooks.toString()); return mBooks; } @Override public void add(Book book) throws RemoteException { mBooks.add(book); //通过监听通知所有的客户端 final int N = backListener.beginBroadcast(); for (int i=0;i<N;i++){ IOnNewBookArrivedListener listener = backListener.getBroadcastItem(i); listener.onNewBookArrived(book); } backListener.finishBroadcast(); Log.e(TAG, "增加一本以后,服务端list : " + mBooks.toString()); } @Override public void registListener(IOnNewBookArrivedListener listener) throws RemoteException { backListener.register(listener); } @Override public void unregistListener(IOnNewBookArrivedListener listener) throws RemoteException { backListener.unregister(listener); } }; @Nullable @Override public IBinder onBind(Intent intent) { return binder; }}用户端:
public class MainActivity extends AppCompatActivity { //由AIDL文件生成的Java类 private IBookManager mBookManager = null; //包含Book对象的list private List<Book> mBooks = new ArrayList<>(); private static String TAG = "MainActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button button = (Button)findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { try { if (mBookManager!=null){ mBooks.add(new Book(23,"新增的")); mBookManager.add(new Book(23,"新增的")); } } catch (RemoteException e) { e.printStackTrace(); } Log.e(TAG, "增加一本以后,客户端list : "+mBooks.toString()); } }); } @Override protected void onResume() { super.onResume(); Intent intent = new Intent(this, AIDLService.class); bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE); } private final ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.e(TAG, "service connected"); //将服务端返回的Binder对象转成AIDL接口,然后通过接口掉方法 mBookManager = IBookManager.Stub.asInterface(service); if (mBookManager != null) { try { mBookManager.registListener(listener); mBooks = mBookManager.getBookList(); Log.e(TAG, "获取客户端list:"+mBooks.toString()); } catch (RemoteException e) { e.printStackTrace(); } } } @Override public void onServiceDisconnected(ComponentName name) { Log.e(TAG, "service disconnected"); } }; private IOnNewBookArrivedListener listener = new IOnNewBookArrivedListener.Stub() { @Override public void onNewBookArrived(Book newBook) throws RemoteException { Log.e(TAG,"监听到服务器加了一个书:"+newBook.toString()); } }; @Override protected void onDestroy() { super.onDestroy(); unbindService(mServiceConnection); }}
6、Binder死亡监听
(1)设置DeathRecipient监听,在binderDied方法中重连远程服务(在Binder线程池中被回调)
(2)在onServiceDisconnected中重连远程服务
7、远程服务的权限验证
(1)例如在清单文件声明权限,在Service的onBind方法中做权限验证
(2)在服务端onTransact方法验证
(3)获取Uid和Pid,验证客户端包名等
注意:由于客户端onServiceConnected和onServiceDisConnected方法运行在UI线程,不能直接进行耗时操作
服务端本身运行在Binder线程池中,可以执行大量的耗时操作。
注:开发艺术探索笔记整理
0 0
- IPC机制(一)
- IPC机制(一)
- 读书笔记--IPC机制(一)
- android IPC机制(一)
- Android IPC机制(一)
- 【2016.04.11】IPC机制(一)
- 安卓IPC机制(一)
- IPC机制--开发艺术探索(一)
- Android IPC机制学习笔记(一)
- 3.IPC 机制(一)
- IPC机制<一>
- IPC机制(一)
- Android——IPC机制(一)IPC概念以及Binder机制
- android IPC机制讲解(一)
- [读书笔记]Android IPC机制(一)
- Android的IPC机制一
- Android中IPC机制(一)
- IPC实现机制(一)---pipe(匿名管道)
- java知识库
- 使用sqoop导入postgresql数据到Hbase
- highcharts绘图之数据库数据绘制柱形图实例
- node 可读流 读取文件百分比显示进度
- Apktool初涉
- IPC机制(一)
- 【Javaweb】笔面试题 ---(1)
- Web开发之CSS布局模型
- SQL高级语句-数据类型
- 来一个完整优化版的走动的时针(canvas绘制)
- 一行一步一花新:python-3:python中的random模块
- 利用反射创建对象
- os、os.path模块中关于文件、目录常用的函数方法
- Windows传输文件格式出错导致解压失败