天天看点

IPC机制———读书笔记IPC机制———读书笔记

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的工作机制图

IPC机制———读书笔记IPC机制———读书笔记

通过书中一实例代码了解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完成。