一、概念
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、创建实体类,实现Parcelablepublic 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和CharSequenceArrayList : 里面的元素必须能被AIDL支持HashMapParcelable:实现了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线程池中,可以执行大量的耗时操作。注:开发艺术探索笔记整理
新闻热点
疑难解答