带你了解android的IPC机制

IPC机制简介

IPC是Inter-Process Communication的缩写,含义就是跨进程通信。
首先我们要理解什么是进程,什么是线程。按操作系统的描述,进程是资源分配的最小单位,而线程是CPU调度的最小单位,一个进程可以包含多个线程(主线程、子线程)。多线程需要考虑并发问题。
Android中的主线程是也叫UI线程,在主线程执行耗时操作会ANR

多进程的两种情况
1 某个应用由于自身原因需要采用多进程模式来实现(如:某些模块由于特殊原因需要运行在独立进程)
2 为了加大一个应用可使用的内存通过多进程来获取多份内存空间

Android中的多进程模式

在正式讲解进程间通信前我们先了解Android中的多进程模式。
通过给四大组件指定android:process属性可以轻易开启多进程(看起来简单,但是有许多需要注意的问题)

一般情况下Android中多进程是指一个应用中存在多个进程的情况。首先在Android使用多进程只有一中方式就是为四大组件指定android:process属性(特例:使用JNI在native底层fork一个新进程)

1 android:process=”:test” (私有进程其他应用组件不可在该进程)
2 android:process=”com.test.l” (全局进程其他组件可用ShareUID方式跑在相同进程中)

UID:在Linux中的代表用户ID,android系统为每个应用分配的标识,也就是说android中的每个应用其实就相当于一个用户。两个应用如果想通过shareUID的方式跑在同一个进程中必须保证UID相同,并且签名一致。那么同进程中就可以相互访问对方的私有数据(如data,res资源,组件信息,内存数据等等)

ShareUID扩展
通过shareduserid来获取系统权限
(1)在AndroidManifest.xml中添加android:sharedUserId=”android.uid.system”
(2)在Android.mk文件里面添加LOCAL_CERTIFICATE := platform(使用系统签名)
(3)在源码下面进行mm编译
这样生成的apk能够获取system权限,可以在任意system权限目录下面进行目录或者文件的创建,以及访问其他apk资源等(注意创建的文件(夹)只有创建者(比如system,root除外)拥有可读可写权限

运行机制与IPC基础

首先我们知道Android系统是基于JVM(Dalvik与ART)
其次系统会为每个进程分配一个独立的虚拟机,意味着进程间的内存的相互独立的

一般来说使用多进程会有几个问题
1 静态成员与单利模式完全失效
2 线程同步机制完全失效
3 SP可靠性下降
4 Application创建多次

问:进程间的对象传递问题怎么解决?
通过IBinder来实现进程间对象的转换

IPC基础概念介绍

主要包含三部分:Serialiazable,Parcelable以及Binder
序列化:将对象转化为字节的过程
Serialiazable:Java提供的序列化接口(标记接口)
Parcelable:android提供的序列化接口
Serialiazable与Parcelable的区别:Serialiazable使用简单但是需要大量I/O操作,Parcelable使用较繁琐,主要用于内存序列化,效率高

Binder
直观的看,Binder是Android中的一个类,实现了IBinder接口
从不同角度理解Binder:
1 从IPC角度,Binder是跨进程通信方式
2 从FrameWork角度,Binder是ServiceManager连接各种Manager(如am,wm等)的桥梁
3 从应用层角度,Binder是客户端与服务端通信的媒介

AIDL的初步了解

1 创建Book.java实体类(实现Parcelable接口,支持内存序列化)
2 创建Book类的aidl声明
3 创建IBookManager的aidl接口

实现Parcelable接口的Book类

public class Book implements Parcelable{
    private int id;
    private String name;
    private double price;

    public Book(int id, String name, double price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }

    public Book() {
    }

    protected Book(Parcel in) {
        id = in.readInt();
        name = in.readString();
        price = in.readDouble();
    }

    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 String toString() {
        return "Book{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", price=" + price +
                '}';
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel parcel, int i) {
        parcel.writeInt(id);
        parcel.writeString(name);
        parcel.writeDouble(price);
    }
}

其实内部是通过Parcel进行对象的转换的,咱们顺便看看Parcel类的描述

Container for a message (data and object references) that can
be sent through an IBinder. A Parcel can contain both flattened data
that will be unflattened on the other side of the IPC (using the various
methods here for writing specific types, or the general
{@link Parcelable} interface), and references to live {@link IBinder}
objects that will result in the other side receiving a proxy IBinder
connected with the original IBinder in the Parcel.

简单的翻译下,Parcel是IBinder发送消息(数据和对象引用)的容器,Parcel可以数据通过各个操作基础类型的方法将数据转化为扁平化传递给IPC的另一端,并且通过IBinder使得对方收到的代理IBinder对象中包裹着原始IBinder。总的说它的作用就是实现对象数据在内存中的传递

Book的aidl声明

package com.example.pangyunxiao.ipcdemo.com.itszt.l;

parcelable Book;

我用的IDE是Android Studio,直接右键创建aidl文件。会自动帮你创建aidl目录,并且将你创建的aidl声明放置到你的项目包名下,如果的eclipse则开发者要自行注意。

IBookManager的声明

package com.example.pangyunxiao.ipcdemo.com.itszt.l;

import com.example.pangyunxiao.ipcdemo.com.itszt.l.Book;
import com.example.pangyunxiao.ipcdemo.com.itszt.l.IOnNewBookAddedListener;
// Declare any non-default types here with import statements

interface IBookManager {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);

            void addBook(in Book book);

            List<Book> getBooks();

            void addBookAndNotify(in Book book);

            void registerListener(IOnNewBookAddedListener l);

            void unregisterListener(IOnNewBookAddedListener l);
}

注意问题
1 实体类的包名与aidl文件的包名必须一致
2 IBookManager中必须import所需实体类
3 接口中声明的方法参数需要使用in/out/inout
4 aidl文件以及实体类在两端都要有,并且同个包下

IBookManager.java简析
接着咱们编译一下项目,会发现自动生成的IBookManager.java类。路径:eclipse中位于gen目录下,as中位于build\generated\source\aidl\debug目录下,接着咱们来简要分析下这个类(由于类比长,就不把代码全贴出来啦)

public interface IBookManager extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements com.example.pangyunxiao.ipcdemo.com.itszt.l.IBookManager {
        private static final java.lang.String DESCRIPTOR = "com.example.pangyunxiao.ipcdemo.com.itszt.l.IBookManager";

        /**
         * Construct the stub at attach it to the interface.
         */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * Cast an IBinder object into an com.example.pangyunxiao.ipcdemo.com.itszt.l.IBookManager interface,
         * generating a proxy if needed.
         */
        public static com.example.pangyunxiao.ipcdemo.com.itszt.l.IBookManager asInterface(android.os.IBinder 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 {
            ...
        }

        private static class Proxy implements com.example.pangyunxiao.ipcdemo.com.itszt.l.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;
            }

            /**
             * Demonstrates some basic types that you can use as parameters
             * and return values in AIDL.
             */
            @Override
            public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException {
                ...
            }

            @Override
            public void addBook(com.example.pangyunxiao.ipcdemo.com.itszt.l.Book book) throws android.os.RemoteException {
                ...
            }

            @Override
            public java.util.List<com.example.pangyunxiao.ipcdemo.com.itszt.l.Book> getBooks() throws android.os.RemoteException {
                ...
            }

            @Override
            public void addBookAndNotify(com.example.pangyunxiao.ipcdemo.com.itszt.l.Book book) throws android.os.RemoteException {
                ...
            }

            @Override
            public void registerListener(com.example.pangyunxiao.ipcdemo.com.itszt.l.IOnNewBookAddedListener l) throws android.os.RemoteException {
                ...
            }

            @Override
            public void unregisterListener(com.example.pangyunxiao.ipcdemo.com.itszt.l.IOnNewBookAddedListener l) throws android.os.RemoteException {
               ...
            }
        }

        static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
        static final int TRANSACTION_getBooks = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
        static final int TRANSACTION_addBookAndNotify = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
        static final int TRANSACTION_registerListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
        static final int TRANSACTION_unregisterListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5);
    }

    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;

    public void addBook(com.example.pangyunxiao.ipcdemo.com.itszt.l.Book book) throws android.os.RemoteException;

    public java.util.List<com.example.pangyunxiao.ipcdemo.com.itszt.l.Book> getBooks() throws android.os.RemoteException;

    public void addBookAndNotify(com.example.pangyunxiao.ipcdemo.com.itszt.l.Book book) throws android.os.RemoteException;

    public void registerListener(com.example.pangyunxiao.ipcdemo.com.itszt.l.IOnNewBookAddedListener l) throws android.os.RemoteException;

    public void unregisterListener(com.example.pangyunxiao.ipcdemo.com.itszt.l.IOnNewBookAddedListener l) throws android.os.RemoteException;
}

DESCRIPTOR:Binder的唯一标识
1 这是个接口类并且集成了IInterface接口,所有可以在Binder中传输的接口都需要继承IIterface接口
2 Stub内部类:是IBookManager类的内部类,就是一个Binder类
asInterface 静态方法:Binder对象转换为接口类型对象
asBinder 非静态方法:接口类型对象转换为Binder对象
onTransact方法:当客户端发起远程调用时,在服务端会执行该方法;参数code:标识调用的方法;参数data:传递的参数;参数reply:用于存储返回值;该方法返回值是boolean表示远程调用是否成功(可做权限验证)
3 Proxy:Stub的内部类,作用是作为IBookManager的代理类(asInterface返回的其实就是它);在该类中主要实现了各个方法的执行流程。例如addBook:方法运行在客户端,首先获取两个Parcel对象(参数_data与返回值_reply),然后把参数信息写入_data中,调用IBinder对象的transact方法发起远程调用,此时当前线程被挂起然后服务器端的onTransact执行,当执行完毕,当前线程继续执行,如果方法有返回值的话通过_reply取得。

注意点
当客户端发起请求时当前线程会被挂起直至服务端返回数据。那么如果一个远程方法是耗时的就不能在UI线程发起远程请求
2 AIDL文件并不是必须的,只是为了方便系统根据aidl文件生存java类,我们可以抛开aidl文件直接写一个Binder
(1创建IBookManager接口类2IBookManager实现类3 Servic中返回)
3 Binder运行在服务端进程,如果服务器进程由于某种原因终止了,那么远程调用将失败(称为Binder死亡),可以通过Binder对象的linkToDeath方法设置死亡代理

流程

实现IPC的方式

怎么实现IPC?其实只要完成它的本质需求,就是在进程之间传递数据,那就算实现了IPC。因此我们有很多种方式可以完成这个目标。实际开发过程中可以选择合适的方式去实现这个数据传递过程。

1 使用Bundle

这是最简单的方式,它就是通过Bundle在不同进程的组件之间传递数据

startActivity(new Intent(...).putExtra("data",bundle));

2 使用文件共享

利用多进程同时读写同个外部文件达到是数据交互的目的
存储形式没有限制:xml,文本,对象序列化等等
缺点:由于Linux系统对文件并发读写没有限制,会导致数据不同步问题,所以该方式只适合于对数据同步要求不高的进程间通信

3 使用共享参数

共享参数是android中一中轻量级存储方案,底层用实现xml文件,系统对它的读写有一定的缓存策略(内存中会有一份sp的备份)在多进程模式下,系统对它的读/写是不可靠的,高并发读/写时有可能会丢失数据

4 使用Messenger

Messenger(信使):在不同的进程之间传递Message对象,是一种轻量级的IPC方案,底层实现就是AIDL
客户端使用服务器的messenger向服务器发消息
服务器使用客户端的messenger向客户端发消息
(类似Handler的使用)
注意Service的隐式启动再5.0+上的问题,需要将隐式Intent转为显式

服务端Handler

public class MessengerHandler extends Handler {

    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        if(msg.what == 1){
            Log.e("MessengerHandler", msg.getData().getString("msg"));
            Messenger client = msg.replyTo;
            Message message = Message.obtain();
            message.what = 1;
            Bundle bundle = new Bundle();
            bundle.putString("reply","shou dao le.");
            message.setData(bundle);
            try {
                client.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }
}

服务端Service

public class MessengerService extends Service {

    Messenger messenger = new Messenger(new MessengerHandler());

    @Override
    public IBinder onBind(Intent intent) {
        return messenger.getBinder();
    }
}

        <service android:name=".MessengerService" android:enabled="true" android:exported="true">
            <intent-filter>
                <action android:name="com.itszt.lww"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </service>

客户端Handler

public class ClientMHandler extends Handler {

    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        if(msg.what == 1){
            String str = msg.getData().getString("reply");
            if (BuildConfig.DEBUG) Log.e("ClientMHandler", str);
        }
    }
}

客户端调起远程服务

intent = new Intent("com.itszt.lww");
        bindService(createExplicitFromImplicitIntent(this,intent),conn, Service.BIND_AUTO_CREATE);

ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            Messenger messenger = new Messenger(iBinder);
            if(messenger == null) return;
            Message message = Message.obtain();
            message.what = 1;
            Bundle bundle = new Bundle();
            bundle.putString("msg","i am a client.");
            message.setData(bundle);
            message.replyTo = new Messenger(new ClientMHandler());
            try {
                messenger.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {

        }
    };

使用AIDL

在上述的AIDL初了解的基础上,咱们来实现简单的AIDL通信。增加一个Service提供给客户端调起,并返回咱们定义IBookManager对应的IBinder对象

public class AIDLService extends Service {

    // 保证高并发问题
    List<Book> books = new CopyOnWriteArrayList<>();
    RemoteCallbackList<IOnNewBookAddedListener> listeners = new RemoteCallbackList<>();

    {
        books.add(new Book(1,"java",66.3));
        books.add(new Book(2,"php",61.3));
        books.add(new Book(3,"c++",65.3));
    }

    IBookManager bookManager = new IBookManager.Stub() {
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }

        @Override
        public void addBook(Book book) throws RemoteException {
            books.add(book);
        }

        @Override
        public List<Book> getBooks() throws RemoteException {
            // 前面我们有提到AIDL只支持ArrayList
            // 那么为什么我们这边可以返回CopyOrWriteArrayList
            // 是这样的,服务器返回的CopyOrWriteArrayList会按List规范生成一个ArrayList传给客户端
            // 类似的还有ConcurrentHashMap
            return books;
        }

        @Override
        public void addBookAndNotify(Book book) throws RemoteException {
            addBook(book);
            if(listeners == null) return;
            int count = listeners.beginBroadcast();
            for(int i = 0;i<count;i++){
                IOnNewBookAddedListener listener = listeners.getBroadcastItem(i);
                listener.onNewBook();
            }
            listeners.finishBroadcast();
        }

        @Override
        public void registerListener(IOnNewBookAddedListener l) throws RemoteException {
            if(listeners == null)
                listeners = new RemoteCallbackList<>();
            listeners.beginBroadcast();
            listeners.register(l);
            listeners.finishBroadcast();
            if (BuildConfig.DEBUG) Log.e("AIDLServiceAdd", "listeners.size():" + listeners.beginBroadcast());
            listeners.finishBroadcast();
        }

        @Override
        public void unregisterListener(IOnNewBookAddedListener l) throws RemoteException {
            if(listeners != null){
                listeners.beginBroadcast();
                listeners.unregister(l);
                listeners.finishBroadcast();
            }
            if (BuildConfig.DEBUG) Log.e("AIDLServiceRemove", "listeners.size():" + listeners.beginBroadcast());
            listeners.finishBroadcast();
        }

    };

    @Override
    public IBinder onBind(Intent intent) {
        return bookManager.asBinder();
    }
}

        <service android:name=".AIDLService" android:enabled="true" android:exported="true">
            <intent-filter>
                <action android:name="com.itszt.aidl"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </service>

客户端调起服务获得IBinder

public class MainActivity extends Activity {

    IBookManager bookManager;
    IOnNewBookAddedListener listener = new IOnNewBookAddedListener.Stub() {
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }

        @Override
        public void onNewBook() throws RemoteException {
            Toast.makeText(MainActivity.this, "收到新书通知啦!!", Toast.LENGTH_SHORT).show();
        }
    };

    Intent intent;
    ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            if(iBinder == null) return;
            bookManager = IBookManager.Stub.asInterface(iBinder);
            if(bookManager == null) return;
            try {
                iBinder.linkToDeath(new IBinder.DeathRecipient() {
                    @Override
                    public void binderDied() {
                        unbindService(conn);
                        bindService(intent,conn,Service.BIND_AUTO_CREATE);
                    }
                },0);
                bookManager.registerListener(listener);
                Toast.makeText(MainActivity.this, bookManager.getBooks().toString(), Toast.LENGTH_SHORT).show();
                bookManager.addBook(new Book(5,"mXx",90));
                bookManager.addBookAndNotify(new Book(5,"mXx",90));
                // Toast.makeText(MainActivity.this, bookManager.getBooks().toString(), Toast.LENGTH_SHORT).show();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        intent = new Intent("com.itszt.aidl");
        bindService(createExplicitFromImplicitIntent(this,intent),conn, Service.BIND_AUTO_CREATE);
    }

    public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) {
        // Retrieve all services that can match the given intent
        PackageManager pm = context.getPackageManager();
        List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);

        // Make sure only one match was found
        if (resolveInfo == null || resolveInfo.size() != 1) {
            return null;
        }

        // Get component info and create ComponentName
        ResolveInfo serviceInfo = resolveInfo.get(0);
        String packageName = serviceInfo.serviceInfo.packageName;
        String className = serviceInfo.serviceInfo.name;
        ComponentName component = new ComponentName(packageName, className);

        // Create a new intent. Use the old one for extras and such reuse
        Intent explicitIntent = new Intent(implicitIntent);

        // Set the component to be explicit
        explicitIntent.setComponent(component);

        return explicitIntent;
    }

    @Override
    protected void onDestroy() {
        if(bookManager!=null && bookManager.asBinder().isBinderAlive()){
            try {
                bookManager.unregisterListener(listener);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        super.onDestroy();
    }
}

AIDL中可以使用的数据类型
基本数据类型(int char double boolean long)
String和CharSequence
List:只支持ArrayList并且每个元素都被aidl支持
Map:只支持HashMap并且每个元素都被aidl支持
Parcelable:所有实现了Pacelable接口的对象
AIDL:所有aidl接口本身也可以在aidl中使用

注意:
1 在AIDL文件中必须显式import所使用到的Parcelable子类以及aidl
2 所有用于AIDL的Parcelable类必须创建一个同名的aidl文件(声明它为Parcelable类型)
3 除了基本数据类型外其他类型的方法参数都必须标识方向(in/out/inout)
不要图方便全部使用inout,因为这在底层实现是有开销的
Stub是服务器与Binder的中介
Proxy是客户端与Binder的中介
多进程间是内存独立的,进程1传递对象A给进程2,Binder会将对象A重新转换生成一个新的对象。对象是不能跨进程直接传输的,对象的跨进程传输本质是序列化
RemoteCallbackLsit是系统专门提供用于管理跨进程Listener的,其内部封装一个Map

6 ContentProvider

ContentProvider 同样可以实现IPC,或者换个说法。ContentProvider 本质就是通过AIDL实现的。只不过它的职责专一,就是为其他应用提供数据的

Binder连接池

在前面说到AIDL的使用及原理的时候,我们可以看到在服务端只是创建了一个Binder然后返回给客户端使用而已。于是我们可以想到是不是我们可以只有一个Service,对于不同可客户端我们只是去返回一个不同的Binder即可,这样就避免了创建了大量的Service。在任玉刚的《android开发艺术探索》给出了一个Binder连接池的概念,很巧妙的避免了Service的多次创建。这个Binder连接池类似于设计模式中的工厂方法模式。为每一个客户端创建他们所需要的Binder对象。那么下面我们看一下它是如何实现的

首先我定义了多个AIDL,总的就是提供BookManager与StudentManager的功能。注意,这边还有个IBinderPool,这个的功能是提供用户选择具体需要的IBinder对象


这里写图片描述

服务端 BinderPoolService 中返回了binderPool对象,客户端可以通过该对象的queryBinder方法获取对应的服务

public class BinderPoolService extends Service {

    public class BookManagerImpl extends IBookManager.Stub{

        List<Book> bs = new CopyOnWriteArrayList<>();
        {
            bs.add(new Book(1,"android",33));
        }

        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }

        @Override
        public List<Book> getBooks() throws RemoteException {
            return bs;
        }
    }

    public class StudentManagerImpl extends IStudentManager.Stub{

        List<Student> ss = new CopyOnWriteArrayList<>();

        {
            ss.add(new Student(1,"lee",19));
        }

        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }

        @Override
        public List<Student> getStudents() throws RemoteException {
            return ss;
        }
    }

    IBookManager bookManager = new BookManagerImpl();
    IStudentManager studentManager = new StudentManagerImpl();

    IBinderPool binderPool = new IBinderPool.Stub() {
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }

        @Override
        public IBinder queryBinder(int binderCode){
            switch (binderCode){
                case 1:
                    return bookManager.asBinder();
                case 2:
                    return studentManager.asBinder();
            }
            return null;
        }
    };

    @Override
    public IBinder onBind(Intent intent) {
        return binderPool.asBinder();
    }
}

客户端的定义了 BinderPool,相当于提供远程服务调用工具类。这边可以考虑使用CountDownLatch将远程服务的连接这个异步操作转为同步

public class BinderPool {

    private Context context;
    private CountDownLatch countDownLatch;
    private static BinderPool binderPool;
    private IBinderPool iBinderPool;

    private BinderPool(Context context) {
        this.context = context;
        // 连接远程线程池服务
        connectBinderPoolService();
    }

    public static BinderPool getInstance(Context context) {
        if (binderPool == null) {
            synchronized (String.class) {
                if (binderPool == null)
                    binderPool = new BinderPool(context);
            }
        }
        return binderPool;
    }

    private synchronized void connectBinderPoolService() {
        // countDownLatch = new CountDownLatch(1);
        Intent intent = new Intent("com.itszt.lwwp");
        context.bindService(ServiceIntentUtil.createExplicitFromImplicitIntent(context, intent),
                conn, Service.BIND_AUTO_CREATE);
//        try {
//            // countDownLatch.await();
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
    }

    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            iBinderPool = IBinderPool.Stub.asInterface(iBinder);
            // countDownLatch.countDown();
            if (null != iBinderPool) {
                try {
                    iBinderPool.asBinder().linkToDeath(deathRecipient, 0);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {

        }
    };

    private IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            if (iBinderPool != null) {
                iBinderPool.asBinder().unlinkToDeath(this, 0);
                iBinderPool = null;
                // 重连
                connectBinderPoolService();
            }
        }
    };

    public IBinder queryBinder(int binderCode) {
        try {
            if (iBinderPool != null)
                return iBinderPool.queryBinder(binderCode);
            return null;
        } catch (RemoteException e) {
            e.printStackTrace();
            return null;
        }
    }
}

客户端通过BinderPool调起远程服务

    new Thread(){
            @Override
            public void run() {
                binderPool = BinderPool.getInstance(MainActivity.this);
            }
        }.start();

    public void onTest(View view) {
        if(binderPool == null) return;
        IBookManager bookManager = IBookManager.Stub.asInterface(binderPool.queryBinder(1));
        IStudentManager studentManager = IStudentManager.Stub.asInterface(binderPool.queryBinder(2));
        try {
            Toast.makeText(this, "bookManager.getBooks():" + bookManager.getBooks().toString(), Toast.LENGTH_SHORT).show();
            Toast.makeText(this, "studentManager.getBooks():" + studentManager.getStudents().toString(), Toast.LENGTH_SHORT).show();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

总结

IPC是什么?是跨进程通信
AIDL是什么?是IPC方式的一种
IPC为什么会导致那么多问题?内存独立
我们在什么时候需要IPC?某功能需要运行在独立进行;提升应用分配内存;应用间交互

源码:http://download.csdn.net/download/javonlee/9931448

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345