【讀書筆記】【Android 開發藝術探索】第 2 章 IPC 機制

一、基礎知識

1.一些概念

IPC : Inter-process Communication 跨進程通信,是指兩個進程之間進行數據交換的過程。

線程:線程是 CPU 調度的最小單元,同時線程是一種有限的系統資源。

進程:一般是指一個執行單元, 在 PC 和移動設備上指一個程序或者一個應用。 進程可以包含多個線程。


2. Android 中的多進程模式

(1).開啓多進程模式

給四大組件在 AndroidManifest 中指定 android:process 屬性,即可開啓。

通過命令行 adb shell ps 可以看見進程信息。

(2).多進程模式的運行機制

系統會爲每一個進程分配一個獨立的虛擬機,不同的虛擬機在內存分配不同的地址空間。

使用多進程會造成的問題:

.靜態成員和單例模式完成失效;

.線程同步機制完成失效;

.SharedPreferences 的可靠性下降;

.Application 會多次創建(因爲運行同一個進程中的組件是屬於同一個虛擬機和同一個 Application 的)


二、IPC 基礎概念介紹

1、Serializable 接口

Serializable 是 Java 提供的一個接口,是一個空接口,爲對象提供標準的序列化和反序列化操作;

serialVersionUID :
用來輔助序列化和反序列化過程的,原則上序列化後的數據中的 serialVersionUID 只有和當前類的 serialVersionUID 相同 才能正常地被反序列化。
 一般手動指定 serialVersionUID 的值,是因爲反序列化時當前類有所改變時,系統會重新計算當前類的 hash 值,並把它賦值 給 serialVersionUID ,這個時候當前類的 serialVersionUID 和反序列化的數據中的 serailVersionUID 不一致,會出現反序列化 失敗,程序會出現 crash。

注意事項:
.靜態成員變量屬於類而不屬於對象,所以不會參與序列化過程;
.用 transient 關鍵字的成員變量不參與序列化過程。

2、Parcelable 接口

Interface for classes whose instance can be written to and restored from a Parcel. Classes implementing the Parcelable interface must also have a non-null static field called CREATOR of the type implements Parcelable.Creator interface.


Serializable 與 Parcelable 的區別與選用

Serializable 開銷大,序列化和反序列化過程需要大量的 I/O 操作,如果是存儲在設備中,網絡傳輸,一般使用 Serializable;

Parcelable 主要用在內存序列化上,是 Android 中的方法。


3、Binder

Binder 是 Android 中的一個類,它實現 IBinder 接口。從 IPC 的角度來說, Binder 是 Android 中的一種跨進程通訊方式。
Android 開發中, Binder 主要用在 Service 中,包括 AIDL 和 Messenger .

三、 Android 中的 IPC 方式

1、使用 Bundle

2、使用文件共享

序列化一個對象到系統文件中,同時從另一個進程中恢復這個對象。

發序列化得到的對象只是在內容上和序列化之前的對象是一樣的,但它們本質上還是兩個對象。

使用文件方式來共享數據對文件格式沒有具體的要求,只要讀寫雙方約定數據格式即可。但是這種方式會面臨併發讀寫的侷限性。

文件共享方式適合在對數據同步要求不高的進程之間進行通信,並且要處理併發讀寫的問題。

系統對 SharedPreference 的讀寫有一定的緩存,在多進程中,SP 面對高併發的讀寫訪問會丟失數據,所以,儘量不要在進程間通信中使用 SP.

3、使用 Messenger

輕量級 IPC 方案,底層實現是 AIDL ,串行處理消息。
例子
服務端進程
public class MessengerService extends Service {
    private static  final  String TAG = "message";

    private static class MessengerHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case Constants.MSG_FROM_CLIENT:
                    Log.i(TAG, "receive msg from Client : " + msg.getData().getString("msg"));

                    // 回覆客服端
                    Messenger client = msg.replyTo;
                    Message replyMessage = Message.obtain(null, Constants.MSG_FROM_SERVICE);
                    Bundle bundle = new Bundle();
                    bundle.putString("reply", "你的消息已收到");
                    replyMessage.setData(bundle);

                    try {
                        client.send(replyMessage);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }

                    break;
                default:
                    break;
            }
        }
    }

    private final Messenger mMessenger = new Messenger(new MessengerHandler());

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

客戶端
public class MessengerActivity extends Activity {

    private static final String TAG = "message";

    private Messenger mMessenger;

    private Messenger mGetReplyMessenger = new Messenger(new MessengerHandler());

    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mMessenger = new Messenger(service);
            Message msg = Message.obtain(null, Constants.MSG_FROM_CLIENT);
            Bundle data = new Bundle();
            data.putString("msg", "Hello, this is client.");
            msg.setData(data);

            msg.replyTo = mGetReplyMessenger;

            try {
                mMessenger.send(msg);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_messenger);

        Intent intent = new Intent(this, MessengerService.class);
        bindService(intent,mConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        unbindService(mConnection);
        super.onDestroy();
    }


    private static class MessengerHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case Constants.MSG_FROM_SERVICE:
                    Log.i(TAG, "receive msg from Service : " + msg.getData().getString("reply"));
                    break;

                default:
                    super.handleMessage(msg);
                    break;
            }
        }
    }
}

在 Messenger 中進行數據傳遞必須將數據放入到 Message 中,而 Messenger 和 Message 都實現了 Parcelable 接口,因此可以跨進程傳輸。

4、使用 AIDL

使用 AIDL 比較複雜,這裏掠過

5、使用 Socket

使用 Socket 通信,首先要聲明權限
<uses-permission android:name="android.permission.INTERNET"/>
 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

其次是不能在主線程中訪問網絡。

四、選用合適的 IPC 方式





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章