【读书笔记】【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 方式





发布了58 篇原创文章 · 获赞 20 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/yxhuang2008/article/details/51295182
今日推荐