Android开发艺术探索-IPC机制

本篇是关于Android开发艺术探索第二章知识IPC机制的读书笔记

什么是IPC机制

IPC 是Inter-Process Communication的缩写,含义为进程间的通信或者是跨进程通信。也就是IPC的使用场景是在多进程情况下。
什么时候要用到多进程呢?

  • 有些模块由于特殊原因需要在单独的进程中运行。
  • 由于Android内存的限制,为了增大内存通过多进程来扩大内存。
  • 我们通过系统提供的ContentProvider查询数据时

注意
多进程或产生以下几个问题

  • 静态成员和单例模式完全失效
  • 线程同步机制完全失效
  • SharedPreference的可靠性下降
  • Application会多次创建

    序列化

    序列化就是将对象转化为字节序列,并能够在以后将字节序列恢复为对象。
  • 当我们使用Intent和Binder传输数据的时候。进行Android开发的时候,无法将对象的引用传给Activities或者Fragments,我们需要将这些对象放到一个Intent或者Bundle里面,然后再传递。
  • 我需要对象持久化到存储设备上
  • 通过网络传输给其他客户端

    Serializable

    Serializable是Java所提供的序列接口
    注意
    记住:对象的序列化是基于字节的,不能使用Reader和Writer等基于字符的层次结构
    这篇文章详细介绍了Serializable的用法
    通常我们使用的时候直接 实现Serializable接口,即可。
    SerialVersionUID的作用
    SerialVersionUID的作用主要是用来表明不同版本的兼容性。
    简单来说,Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来 的字节流中的serialVersionUID与本地相应实体(类)的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序 列化,否则就会出现序列化版本不一致的异常。

当实现java.io.Serializable接口的实体(类)没有显式地定义一个名为serialVersionUID,类型为long的变 量时,Java序列化机制会根据编译的class自动生成一个serialVersionUID作序列化版本比较用,这种情况下,只有同一次编译生成的 class才会生成相同的serialVersionUID 。

如果我们不希望通过编译来强制划分软件版本,即实现序列化接口的实体能够兼容先前版本,未作更改的类,就需要显式地定义一个名为serialVersionUID,类型为long的变量,不修改这个变量值的序列化实体都可以相互进行串行化和反串行化。

Serializable的使用
如果我们想要序列化一个对象,首先要创建某些OutputStream(如FileOutputStream、ByteArrayOutputStream等),然后将这些OutputStream封装在一个ObjectOutputStream中。这时候,只需要调用writeObject()方法就可以将对象序列化,并将其发送给OutputStream(记住:对象的序列化是基于字节的,不能使用Reader和Writer等基于字符的层次结构)。而反序列的过程(即将一个序列还原成为一个对象),需要将一个InputStream(如FileInputstream、ByteArrayInputStream等)封装在ObjectInputStream内,然后调用readObject()即可。

ByteArrayOutputStream
字节数组输出流在内存中创建一个字节数组缓冲区,所有发送到输出流的数据保存在该字节数组缓冲区中。
具体使用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class SerializableTest {
public static void main(String[] args) {
Animal animal = new Animal("cat", 10);

try {
//序列化-FileOutputStream
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("animal.out"));
outputStream.writeObject(animal);
outputStream.writeObject("hhhh");
outputStream.close();

//反序列化-FileInputStream
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("animal.out"));
Animal animal2 = (Animal) inputStream.readObject();
inputStream.close();
System.out.println(animal2.name);
System.out.println(animal2.age);

//序列化-ByteArrayOutputStream
ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream outputStream2 = new ObjectOutputStream(arrayOutputStream);
outputStream2.writeObject(animal);
outputStream2.flush();

//反序列化-ByteArrayInputStream
ObjectInputStream inputStream2 = new ObjectInputStream(new ByteArrayInputStream(arrayOutputStream.toByteArray()));
Animal animal3 = (Animal) inputStream2.readObject();
inputStream2.close();
System.out.println(animal3.name);
System.out.println(animal3.age);


} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}

class Animal implements Serializable{
String name ;
int age;
public Animal(String name,int age){
this.name = name;
this.age = age;
}
}

在这里我们还需要注意的是:
反序列化的对象不会重新调用构造函数。Serializable对象,对象完全以它存储的二进制位作为基础来构造,而不用构造函数。

序列化前的对象和序列化后的对象是深复制关系。反序列化还原后的对象地址与原来的地址不同。但是内容是一样的,而且对象中包含的引用也是相同。

Parcable

主要是以下几个自动生成的函数

  • Parcelable(Parcel in) //初始化数据
  • Creator CREATOR = new Creator{
    createFromParcel(Parcel in){

    return new ParcelableTest(in);
    

    }
    }

  • describeContents()

  • writeToParcel(Parcel dest ,int flags)//写入到Parcel中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public class Person implements Parcelable {
private String name;
private int age;

protected Person(Parcel in) {
name = in.readString();
age = in.readInt();
}

public static final Creator<Person> CREATOR = new Creator<Person>() {
@Override
public Person createFromParcel(Parcel in) {
return new Person(in);
}

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

//返回值为0或者CONTENTS_FILE_DESCRIPTOR
//用于指示Parcelable中封装的特殊类型
@Override
public int describeContents() {
return 0;
}

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

public Person() {

}

public String getName() {
return name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public void setName(String name) {
this.name = name;
}
}

FirstActivity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class FirstActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first_layout);

}

public void startSecond(View view){
Person person = new Person();
person.setAge(10);
person.setName("cat");

Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
intent.putExtra("person", person);
startActivity(intent);
}
}

SecondActivity

1
2
3
4
5
6
7
8
9
10
11
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second_layout);
Intent intent = getIntent();
Person person = (Person) intent.getParcelableExtra("person");
TextView textView = findViewById(R.id.text);
textView.setText(person.getAge()+"="+person.getName());
}
}

我们可以通过上面的方式进行Intent传递数据。

Serializable和Parcelable的对比

Android应尽量采用Parcelable,效率至上
Parcelable的速度是Serializable十倍以上,但是Serializable的代码量比较少,写起来方便。但是使用了反射,序列化过程慢。
Parcelable的实现原理是将一个完整的对象进行分解。而分解后的每一部分都是Intent所支持的数据类型,这样也就实现传递对象的功能了

0%