天天看點

【讀書筆記】【Android 開發藝術探索】第 2 章 IPC 機制一、基礎知識1.一些概念二、IPC 基礎概念介紹三、 Android 中的 IPC 方式四、選用合适的 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 方式

【讀書筆記】【Android 開發藝術探索】第 2 章 IPC 機制一、基礎知識1.一些概念二、IPC 基礎概念介紹三、 Android 中的 IPC 方式四、選用合适的 IPC 方式

繼續閱讀