帶你了解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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。