IPC机制———读书笔记

来源:互联网 发布:甬商贷网络借贷 编辑:程序博客网 时间:2024/05/22 11:46

IPC机制———读书笔记

IPC(Inter-Process Communication)是指两个进程之间进行数据交换的过程。

Android中的多进程模式

开启多进程模式

给四大组件在AndroidMenifest中指定android:process属性。
书中代码如下:

    <activity        android:name=".SecondActivity"        android:configChanges="screenLayout"        android:label="@string/app_name"        android:process=":remote" />    <activity        android:name=".ThirdActivity"        android:configChanges="screenLayout"        android:label="@string/app_name"        android:process="com.ryg.chapter_2.remote" />

多进程模式的运行机制

所有运行在不同进程中的四大组件,只要它们之间需要通过内存来共享数据,都会共享失败,这也是多进程带来的主要影响。
多进程会造成如下问题:
1.静态成员和单例模式完全失效
2.线程同步机制完全失效
3.SharedPreferences的可靠性下降
4.Application会多次创建
不同进程的组件会拥有独立的虚拟机、Application以及独立空间。

IPC基础概念介绍

主要包括:Serializable接口、Parcelable接口以及Binder

Serializable接口、Parcelable接口区别

Serializable是java中的序列化接口,使用起来方便但是开销大,序列化和反序列化过程需要大量I/O操作。而Parcelable是Android中的序列化方式,更适合用于Android平台上,它的效率高主要用在内存序列化上。

Binder的工作机制图

这里写图片描述
通过书中一实例代码了解Binder:

public interface IBookManager extends android.os.IInterface {/** Local-side IPC implementation stub class. */    public static abstract class Stub extends android.os.Binder implements com.ryg.chapter_2.aidl.IBookManager {        private static final java.lang.String DESCRIPTOR = "com.ryg.chapter_2.aidl.IBookManager";        /** Construct the stub at attach it to the interface. */        public Stub() {            this.attachInterface(this, DESCRIPTOR);        }        /**         * Cast an IBinder object into an com.ryg.chapter_2.aidl.IBookManager interface,         * generating a proxy if needed.         */        public static com.ryg.chapter_2.aidl.IBookManager asInterface(android.os.IBinder obj) {            if ((obj==null)) {                return null;            }            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);            if (((iin!=null)&&(iin instanceof com.ryg.chapter_2.aidl.IBookManager))) {                return ((com.ryg.chapter_2.aidl.IBookManager)iin);            }            return new com.ryg.chapter_2.aidl.IBookManager.Stub.Proxy(obj);        }        @Override        public android.os.IBinder asBinder(){            return this;        }        @Override         public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {            switch (code) {                case INTERFACE_TRANSACTION: {                    reply.writeString(DESCRIPTOR);                    return true;                }                case TRANSACTION_getBookList: {                    data.enforceInterface(DESCRIPTOR);                    java.util.List<com.ryg.chapter_2.aidl.Book> _result = this.getBookList();                    reply.writeNoException();                    reply.writeTypedList(_result);                    return true;                }                case TRANSACTION_addBook: {                    data.enforceInterface(DESCRIPTOR);                    com.ryg.chapter_2.aidl.Book _arg0;                    if ((0!=data.readInt())) {                        _arg0 = com.ryg.chapter_2.aidl.Book.CREATOR.createFromParcel(data);                    }                    else {                        _arg0 = null;                    }                    this.addBook(_arg0);                    reply.writeNoException();                    return true;                }                case TRANSACTION_registerListener: {                    data.enforceInterface(DESCRIPTOR);                    com.ryg.chapter_2.aidl.IOnNewBookArrivedListener _arg0;                    _arg0 = com.ryg.chapter_2.aidl.IOnNewBookArrivedListener.Stub.asInterface(data.readStrongBinder());                    this.registerListener(_arg0);                    reply.writeNoException();                    return true;                }                case TRANSACTION_unregisterListener: {                    data.enforceInterface(DESCRIPTOR);                    com.ryg.chapter_2.aidl.IOnNewBookArrivedListener _arg0;                    _arg0 = com.ryg.chapter_2.aidl.IOnNewBookArrivedListener.Stub.asInterface(data.readStrongBinder());                    this.unregisterListener(_arg0);                    reply.writeNoException();                    return true;                }            }            return super.onTransact(code, data, reply, flags);        }        private static class Proxy implements com.ryg.chapter_2.aidl.IBookManager {            private android.os.IBinder mRemote;            Proxy(android.os.IBinder remote){                mRemote = remote;            }            @Override             public android.os.IBinder asBinder(){                return mRemote;            }            public java.lang.String getInterfaceDescriptor(){                return DESCRIPTOR;            }            @Override             public java.util.List<com.ryg.chapter_2.aidl.Book> getBookList() throws android.os.RemoteException {                android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                java.util.List<com.ryg.chapter_2.aidl.Book> _result;                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);                    _reply.readException();                    _result = _reply.createTypedArrayList(com.ryg.chapter_2.aidl.Book.CREATOR);                }                finally {                    _reply.recycle();                    _data.recycle();                }                return _result;            }            @Override             public void addBook(com.ryg.chapter_2.aidl.Book book) throws android.os.RemoteException {                android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    if ((book!=null)) {                        _data.writeInt(1);                        book.writeToParcel(_data, 0);                    }                    else {                        _data.writeInt(0);                    }                    mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);                    _reply.readException();                }                finally {                    _reply.recycle();                    _data.recycle();                }            }            @Override            public void registerListener(com.ryg.chapter_2.aidl.IOnNewBookArrivedListener listener) throws android.os.RemoteException {                android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    _data.writeStrongBinder((((listener!=null))?(listener.asBinder()):(null)));                    mRemote.transact(Stub.TRANSACTION_registerListener, _data, _reply, 0);                    _reply.readException();                }                finally {                    _reply.recycle();                    _data.recycle();                }            }            @Override             public void unregisterListener(com.ryg.chapter_2.aidl.IOnNewBookArrivedListener listener) throws android.os.RemoteException {                android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    _data.writeStrongBinder((((listener!=null))?(listener.asBinder()):(null)));                    mRemote.transact(Stub.TRANSACTION_unregisterListener, _data, _reply, 0);                    _reply.readException();                }                finally {                    _reply.recycle();                    _data.recycle();                }            }        }        static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);        static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);        static final int TRANSACTION_registerListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);        static final int TRANSACTION_unregisterListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);    }    public java.util.List<com.ryg.chapter_2.aidl.Book> getBookList() throws android.os.RemoteException;    public void addBook(com.ryg.chapter_2.aidl.Book book) throws android.os.RemoteException;    public void registerListener(com.ryg.chapter_2.aidl.IOnNewBookArrivedListener listener) throws android.os.RemoteException;    public void unregisterListener(com.ryg.chapter_2.aidl.IOnNewBookArrivedListener listener) throws android.os.RemoteException;}

代码具体解析这里就不贴了,可以查看书中讲解。
需要注意:
1.当客户端发起远程请求时,由于当前线程会被挂起直至服务端进程返回数据,所以一个远程方法是很耗时的,不能在UI线程中发起此请求。
2.由于服务端的Binder方法运行在Binder线程池中,所以Binder方法不管是否耗时都应该采用同步的方式去实现。

Android中的IPC方式

1.Bundle
2.文件共享(不建议使用系统的SharedPreferences)
3.Messenger(轻量级IPC,底层依然是AIDL)工作原理(Page70 & 代码)
4.AIDL4.1. AIDL支持的数据类型:基本数据类型;String和CharSequence;List只支持ArrayList,里面每个元素都必须被AIDL支持;Map只支持HashMap,里面每个元素都必须被AIDL支持(包括key和value);Parcelable;AIDL接口本身;4.2. 服务端可以使用CopyOnWriteArrayList和ConcurrentHashMap来进行自动线程同步,客户端拿到的依然是ArrayList和HashMap;4.3. 服务端和客户端之间做监听器,服务端需要使用RemoteCallbackList,否则客户端的监听器无法收到通知(因为服务端实质还是一份新的序列化后的监听器实例,并不是客户端那份);dd. 客户端调用远程服务方法时,因为远程方法运行在服务端的binder线程池中,同时客户端线程会被挂起,所以如果该方法过于耗时,而客户端又是UI线程,会导致ANR,所以当确认该远程方法是耗时操作时,应避免客户端在UI线程中调用该方法。同理,当服务器调用客户端的listener方法时,该方法也运行在客户端的binder线程池中,所以如果该方法也是耗时操作,请确认运行在服务端的非UI线程中。另外,因为客户端的回调listener运行在binder线程池中,所以更新UI需要用到handler。4.4. 客户端通过IBinder.DeathRecipient来监听Binder死亡,也可以在onServiceDisconnected中监听并重连服务端。区别在于前者是在binder线程池中,访问UI需要用Handler,后者则是UI线程。4.5. 可通过自定义权限在onBind或者onTransact中进行权限验证。
5.ContentProvider
6.Socket 一般用于网络通信,AIDL用这种方式会过于繁琐,不建议。
7.Binder连接池,通过BinderPool的方式将Binder的控制与Service本身解耦,同时只需要维护一份Service即可。这里用到了CountDownLatch,大概解释下用意:线程在await后等待,直到CountDownLatch的计数为0,BinderPool里使用它的目的是为了保证Activity获取BinderPool的时候Service已确定bind完成。

0 0
原创粉丝点击