美文网首页
IPC机制(一)——IPC基础概念

IPC机制(一)——IPC基础概念

作者: 李die喋 | 来源:发表于2019-10-05 13:04 被阅读0次

    Android中的多进程

    IPC学过操作系统的都应该知道,就是进程间通信或者跨进程通信。Android是基于Linux内核的移动操作系统,它的进程间通信方式并不是完全继承于Linux,它有自己的进程间通信方式。

    多进程通信的主要方式

    • Binder
    • Bundle
    • 文件共享
    • AIDL
    • Messenger
    • ContentProvider
    • Socket

    开启多进程模式

    Android中使用多进程只有一种方法,就是给四大组件在AndroidMenifest中指定android:process属性,除此之外没有其他办法。但有一种非常规的办法就是通过JNI在native层去fork一个新的进程。fork在linux系统上就可以尝试。

    <activity>
        <android:process=":remote"/>
        或者
        <android:process="com.lxy.ipc.remote"/>
    </activity>
    

    两种方式的区别:

    以“:”开头的是一种简写的方法,完整的进程名称是com.lxy.ipc:remote。也就是在当前进程名前加上了当前的包名。且以“:”开头的进程属于当前进程的私有进程,其它应用组件不可以和它跑在同一进程中。

    第二中命名方式是完整的命名方式,不会附加包名信息,属于全局进程,其它应用可以通过sharedUserID和它跑在同一进程中。

    //第一个程序的menifest文件
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.lxy.client"
        android:versionCode="1"
        android:versionName="1.0"
        android:sharedUserId="com.lxy.share">
        
    //第二个程序的menifest文件
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.lxy.service"
        android:versionCode="1"
        android:versionName="1.0"
        android:sharedUserId="com.lxy.share">   
    

    多进程模式的运行机制

    在学操作系统的时候我们知道每一个进程的都有自己的进程控制块(PCB),android在多进程模式中,不同进程的组件有自己独立的虚拟机、Application、内存空间

    举个例子来说:

    UserManager类中有一个静态变量

    public static int userId = 1;
    

    按理来说静态变量应该是被所有地方共享的,在一个进程中进行加一操作,在其他进程打印,发现结果为1。这说明多进程不是添加了一个android:process属性这么简单。每一个进程都有一个独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,这会导致在不同的虚拟机中访问同一个类对象(静态变量属于类对象)会产生多份副本

    不同进程中的组件几乎都需要共享数据。使用多进程会造成如下几方面的问题:

    • 静态成员和单例模式完全失效

    分配不同的虚拟机,产生多个对象副本

    • 进程同步机制完全失效

    不在同一块内存中,所以锁对象和锁全局类都达不到效果

    • SharedPreferences的可靠性下降

    SP不支持两个进程同时执行写操作,否则会导致数据一定几率的丢失。SP的底层是通过读写XML来文件实现的,并发写/读都可能出现问题。

    • Application会多次创建

    创建新的进程就是要分配独立的虚拟机,所以就是启动一个新的应用的过程,重新启动就会创建新的Application。

    Serializable

    Serializable是java提供的一个序列化接口,是一个空接口。

    public class User implements Serializable {
        private static final long serialVersionUID = 1L;
        private String name;
        private int age;
        、、、
    }
    

    序列化和反序列化过程:

    //序列化
    User user = new User("ldd",20);
    ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("cache.txt"));
    out.writeObject(user);
    out.close();
    
    //反序列化
    ObjectInputStream in = new ObjectInputStream(new FileInputStream("cache.txt"));
    User newUser = (User) in.readObject();
    in.close();
    

    序列化就是:将对象转化为字节序列的过程

    反序列化就是:将字节序列恢复为java对象

    在User类中有一个变量serialVersionUID是用来辅助序列化的过程。原则上序列化后的数据中的serialVersionUID只有和当前类的serialVersionUID相同才能够被反序列化。当我们不指定它的值时,可以让编译器根据当前类的结构去生成它的值,但是这样容易出现错误。比如,当前对象序列化后,更改了类中的变量,再反序列化的时候就会出现错误。因为更改类后会重新生成一个新值。所以一般serialVersionUID的值手动设置,类改变了反序列化也不会出错。

    注意:

    • 静态变量属于类不属于对象,不会参与序列化过程
    • 用transient关键字标记的成员变量不参与序列化过程

    Parcelable接口

    实现这个接口,一个类的对象就可以实现序列化并可以通过Intent和Binder传递。

    public class User implements Parcelable {
            private String name;
            private int age;
            private Book book;
    
            public User(String name,int age){
                this.name = name;
                this.age = age;
            }
    
            protected User(Parcel in) {
                name = in.readString();
                age = in.readInt();
                book = in.readParcelable(Thread.currentThread().getContextClassLoader());
            }
    
            public static final Creator<User> CREATOR = new Creator<User>() {
                @Override
                public User createFromParcel(Parcel in) {
                    return new User(in);
                }
    
                @Override
                public User[] newArray(int size) {
                    return new User[size];
                }
            };
    
            @Override
            public int describeContents() {
                return 0;
            }
            
            /**
            *Parcel内部包装了可序列化的数据
            *将当前对象写入序列化结构中
            *flags == 1:表示当前对象需要作为返回值返回
            * flags == 0:几乎所有情况都为0
            */
            @Override
            public void writeToParcel(Parcel dest, int flags) {
                dest.writeString(name);
                dest.writeInt(age);
                dest.writeParcelable(book,0);
            }
    }
    

    序列化过程实现的工能:

    • 序列化

    writeToParcel(Parcel out,int flags)

    • 反序列化

    由CREATOR完成,内部创建了序列化对象和数组。

    • 内容描述

    describeContents

    返回当前对象的内容描述符(FileDescriptor)。若有返回1,若无返回0。一般都返回0。

    Serializable和Parcelable比较

    Serializable Parcelable
    使用简单但开销大 使用复杂但效率高
    需要大量I/O操作 用在内存序列化上(存储设备、网络传输)

    相关文章

      网友评论

          本文标题:IPC机制(一)——IPC基础概念

          本文链接:https://www.haomeiwen.com/subject/xlgepctx.html