本文为学习笔记,所用的图片、案例均为教学视频截图
源视频地址:Android开发基础教程(2019)第35集 序列化(1)
作者:longway777
何为序列化
将对象转换为字节序列,完整的保存在磁盘上,或者通过网络发送出去。
反序列化就是将对象重新创建出来
序列化的三种方式
Serializable
java自带的接口,使用起来很简单,只需要一句话的标注就可以,具体实现也不需要做,全部是由jdk完成。缺点是效率不高,但对于应用程序级别已经够用。
Parcelable
专为安卓定制,深度优化,效率很高,在安卓系统的底层扮演了非常重要的角色,进程调度交换数据,交换对象等必不可少。
Json
基于文本的序列化,相对于二进制文件文本具有很高的可读性,广泛应用。
效果演示
本篇章先使用第一个方法,Serializable 实现对象的序列化以及反序列化。
通过输入内容,点击Save按钮后将对象保存在文件中(序列化),点击load读取文件中的内容,反序列化使对象重建并显示在屏幕上。
一、创建界面
二、创建student类
创建student类,包含属性名字、姓名、分数等,类要实现接口:Serializable。并且设置getter、setter,实现构造方法等。(具体看最后的源码)
alt+insert,选择构造,创建他们三个的构造方法。
完成他们的setter和gerter
三、点击按钮创建对象写入到文件中
try catch
没有处理可能发生的异常
这种IO的操作,包括像是网络的操作,是不可靠的,不一定成功,可能会出错(比如文件不存在,磁盘故障),所以需要做异常处理避免应用程序产生异常而崩溃。
尝试执行
尝试执行try里面的内容,如果不成功就会返回一个异常值,这里把他打印出来。
举一个很简单的例子
并且程序没有闪退
SAVE完成后,点击执行:
在文件系统中可以找到创建的文件
是二进制序列的字节文件,看着像是乱码
可以用hex转换工具大致看看
toast的快速自动补全
输入Toast按下tab键自动补全
四、点击按钮反序列化重建对象
可能的错误,两个catch
快速try
点击按钮后反序列化并且对象重建在屏幕上
关键代码
虽然代码看似很多,但序列化真正涉及到的就是序列化后写入文件中,然后反序列化读出来,还有类要继承的接口。
student.java
创建student类,包含属性名字、姓名、分数等,类要实现接口:Serializable。并且设置getter、setter,实现构造方法等。
//如果某个属性不需要序列化,可以添加关键字:transient
public class Student implements Serializable {
private String name;
private int age;
private Score score;
public Student(String name, int age, Score score) {
this.name = name;
this.age = age;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Score getScore() {
return score;
}
public void setScore(Score score) {
this.score = score;
}
}
class Score implements Serializable{
private int math;
private int english;
private int chinese;
private String grade;
public Score(int math, int english, int chinese) {
this.math = math;
this.english = english;
this.chinese = chinese;
if(math>=90 && english>=90 && chinese>=90){
this.grade = "A";
}else if(math>=80 && english>=80 && chinese>=80){
this.grade = "B";
}else {
this.grade = "C";
}
}
public int getMath() {
return math;
}
public void setMath(int math) {
this.math = math;
}
public int getEnglish() {
return english;
}
public void setEnglish(int english) {
this.english = english;
}
public int getChinese() {
return chinese;
}
public void setChinese(int chinese) {
this.chinese = chinese;
}
public String getGrade() {
return grade;
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
EditText editTextName,editTextAge,editTextMath,editTextEnglish,editTextChinese;
Button buttonSave,buttonLoad;
TextView textViewGrade;
//定义文件名为一个常量
private static final String FILE_NAME = "myfile.data";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*引入一个错误,观察try catch的机制
int x = 5;
//除以0是算数上的一个错误,应用程序会马上崩溃闪退
try {
x = x / 0;
// 错误类型为算数错误
}catch (ArithmeticException e){
Log.e("calError", "onCreate: "+e);
}*/
editTextName = findViewById(R.id.name);
editTextAge = findViewById(R.id.age);
editTextMath = findViewById(R.id.math);
editTextEnglish = findViewById(R.id.eng);
editTextChinese = findViewById(R.id.chinese);
buttonSave = findViewById(R.id.button);
buttonLoad = findViewById(R.id.button2);
//之前因为缺少这一句,导致对象没有实例化所以软件闪退
textViewGrade = findViewById(R.id.textView);
buttonSave.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//点击保存后,创建变量,对象保存数据
int math = Integer.valueOf(editTextMath.getText().toString());
int english = Integer.valueOf(editTextEnglish.getText().toString());
int chinese = Integer.valueOf(editTextChinese.getText().toString());
Score score = new Score(math,english,chinese);
String name = editTextName.getText().toString();
int age = Integer.valueOf(editTextAge.getText().toString());
Student student = new Student(name,age,score);
try {
//将对象序列化写入到文件中,借助下面这个接口,针对应用程序而言,是输出,输出到文件中
// 第一个参数是文件的名称,第二个是读写的模式(这里选择覆盖)
ObjectOutputStream objectOutputStream = new ObjectOutputStream(openFileOutput(FILE_NAME,MODE_PRIVATE));
//把对象写入文件
objectOutputStream.writeObject(student);
objectOutputStream.flush();//清空缓冲区
objectOutputStream.close();
Toast.makeText(MainActivity.this,"data saved!",Toast.LENGTH_SHORT).show();
//sava之后把页面数据清空用来呈现load的数据
editTextChinese.getText().clear();
editTextEnglish.getText().clear();
editTextMath.getText().clear();
editTextName.getText().clear();
editTextAge.getText().clear();
textViewGrade.setText("-");
//抓住的错误类型为IOException
}catch (IOException e){
//这里不做其他处理,仅观察
Log.e("IO", "IO error " , e);
}
}
});
//读取,反系列化
buttonLoad.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
ObjectInputStream objectInputStream = new ObjectInputStream(openFileInput(FILE_NAME));
// 类型强制转换为Student类
Student student = (Student)objectInputStream.readObject();
//对象重建显示在页面上
editTextName.setText(student.getName());
editTextAge.setText(String.valueOf(student.getAge()));
editTextMath.setText(String.valueOf(student.getScore().getMath()));
editTextEnglish.setText(String.valueOf(student.getScore().getEnglish()));
editTextChinese.setText(String.valueOf(student.getScore().getChinese()));
textViewGrade.setText(student.getScore().getGrade());
} catch (IOException | ClassNotFoundException e) {
Log.e("IO", "onClick: ", e);
}
}
});
}
}