天天看点

跨进程通信使用总结(一)_跨进程通信基础篇

跨进程通信基础篇

含义:

跨进程通信,是指两个进程之间数据交换的过程,英文全称 Inter-Process Communication 缩写IPC

进程和线程的关系:

在移动设备上,一个程序或者一个应用,就是一个进程,一个进程里面可以包含多个线程

(例如:一个应用里面有一个主线程(用于更新UI)和多个子线程(执行耗时的任务))

开启多线程的方法:

在Android中开启多进程只有一种方法: 那就是给4大组件(Activity,Service,Receiver,ContentProvider)在Menifest中指定android:process属性,除此之外没有其他的方法(通过JNI在native层去fork一个新进程除外)

实例1如下:

<activity
    android:name=".activity.Main2Activity"
    android:process=":remote1" />
           

实例2如下:

<activity
    android:name=".activity.Main3Activity"
    android:process="com.hlj.demo.remote2" />
           

说明:

1.首先实例1中 ":“的含义是指:这是一种简写

a.当前的进程名称前面要附加上当前的包名 进程完整名称:com.hlj.demo:remote1

b.以”:"开头的进程属于当前应用的私有进程,其他应用的组件不可以和它跑在同一个进程中

2,实例2中的进程名称是一种完整的命名方式,不会附加包名信息,其次它属于全局进程,其他应用通过ShareUID方式可以和它跑在同一个进程中.(2个应用的签名也要相同)

注意:

程序入口MainActivity,默认没有给它process属性,那么它就运行在默认的进程中,默认的进程名称是包名,如果给它指定了process属性,那么它就运行在该指定进程当中

如何查看自己开启了多少个进程呢,studio如下图所示:

跨进程通信使用总结(一)_跨进程通信基础篇

运行在同一个进程中的组件是属于同一个虚拟机和同一个Application,可以共享Applicaiton下的数据,运行在不同进程中的组件是属于2个不同的虚拟机和2个不同的Application,2个不同的Application数据是不能互通的

IPC的基础概念: Serializable接口,Parcelable接口,Binder

Serializable接口:Serializable是java所提供的一个序列化的接口,它是一个空接口,为对象提供序列化和反序列化操作

//实现Serializable接口即可
public class UserBean implements Serializable{
    private static final long serialVersionUID=1L;
    public String name;
}
           
UserBean user = new UserBean();
user.name = "hao123";
if (!StrUtils.IsKong(Environment.getExternalStorageDirectory() + "/" + "demo")) {
      String baseExternalStoragepath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + "demo";
      baseDirectory = new File(baseExternalStoragepath);
      if (!baseDirectory.exists()) {
          //先创建文件夹
          baseDirectory.mkdirs();
      }
      //再创建文件
      File wejian = new File(baseDirectory.getPath() + "/" + "user.txt");
      if (!wejian.exists()) {
          wejian.createNewFile();
      }
      //序列化到文件中
      ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(wejian));
      out.writeObject(user);
      out.flush();
      out.close();   
  }


 //反序列化,从文件中读取文件
  File wejian=new File(baseDirectory.getPath()+"/"+"user.txt");
  ObjectInputStream in=new ObjectInputStream(new FileInputStream(wejian));
  UserBean user=(UserBean)in.readObject();
  in.close();
           

注意:

序列化和反序列化需要读写文件,所以需要在清单文件配置读写权限,大于6.0的设备还要动态申请权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
           

serialVersionUID:

一般来说我们应该手动指定serialVersionUID的值,这样做的好处是:当版本升级后,我们可能删除了某个成员变量也可能增加了一些新的成员变量,但指定了这个值以后,反序列化还是可以成功,程序可以最大限度的恢复数据,如果不指定serialVersionUID的值的话,程序会挂掉,但是如果类结构发生了非常规性的改变,例如修改了成员变量的类型结构,这种毁灭性的改变后,反序列化还是会失败,因为无法从老版本的数据中还原一个新的类型结构的对象

注意:

1,静态成员属于类不属于对象,所以不会参与序列化的过程

2,用transient关键字标记的成员变量不会参与序列化的过程

Parcelable接口

Parcelable 是android中提供的新的序列化方式,只要实现这个接口,一个类的对象就可以实现序列化,并且可以通过Intent和Binder传输

实例如下:

public class User2 implements Parcelable {
    public  int age;
    //体重
    public  int weight;
    public  String name;
    public Book book;

    public User2(){
    
    }

    public User2(Parcel in) {
    //注意:这里读取字段的属性要和写入字段的顺序一样 age,weight,name,book
        age=in.readInt();
        weight=in.readInt();
        name=in.readString();
        //由于book是另一个序列化对象,所以它的反序列化的过程要传递当前上下文类加载器
        book= in.readParcelable(Thread.currentThread().getContextClassLoader());
        
    }

    //studio会自动生成这里
    public static final Creator<User2> CREATOR = new Creator<User2>() {
        @Override
        public User2 createFromParcel(Parcel in) {
            return new User2(in);
        }

        @Override
        public User2[] newArray(int size) {
            return new User2[size];
        }
    };

    //studio会自动生成这里
    @Override
    public int describeContents() {
        return 0;
    }


    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(age);
        dest.writeInt(weight);
        dest.writeString(name);
        dest.writeParcelable(book,0);
    }
}

           

说明:

1,从Parcel in里面读取字段的顺序一定要和writeToParcel字段的顺序一样(否则同一个类型的字段例如age和weight数据会搞混)

2,由于Book是另一个序列化对象,所以它的反序列化的过程要传递当前上下文类加载器

Parcelable接口和Serializable接口的比较

共同点:都能实现序列化并且都可用于Intent间的数据传递

不同点:Serializable是java中提供的接口,使用起来更加简单,但是开销很大,需要大量的IO操作,Parcelable是android中的序列化方式,所以更适用与android平台,缺点是使用起来稍微麻烦一点,优点是效率高

Binder:

直观来讲,Binder是android中的一个类,它实现了IBinder接口.从IPC的角度来讲,Binder是Android中的一种跨进程通信方式,从AndroidFramework角度来讲,Binder是ServiceManager连接各种Manager(ActivityNamager,WindowManger等等)的桥梁;从Android应用层来讲,Binder是客户端和服务端进行通信的媒介,当binderService的时候,服务端会返回一个包含服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包含普通的服务和基于AIDL的服务,普通的service服务不涉及进程间通信,主要是AIDL会涉及binder的核心

结尾:

下一篇会总结跨进程通信的几种方式,尽情期待啦~^^

继续阅读