Android中序列化的实现有两种方式:Serializable接口和Parcelable接口,本文对这两种方式进行简单的总结和使用。

一.相关概念

(一)序列化的原因(序列化能实现的效果)

1.永久性保存对象,保存对象的字节序列到本地文件中;

2.对象在网络中传递;

3.对象在IPC间传递。

(二)序列化的方法

android系统中关于序列化的方法一般有两种,分别是实现Serializable接口和Parcelable接口,其中Serializable接口是来自Java中的序列化接口,而Parcelable是Android自带的序列化 接口。 上述的两种序列化接口都有各自不同的优缺点,我们在实际使用时需根据不同情况而定。

1.当需要内存较多时使用Parcelable接口。

Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC,而相比之下 Parcelable的性能更高(毕竟是Android自带的),所以当在使用内存时(如:序列化对象在网络中传递对象或序列化在进程间传递对象),更推荐使用Parcelable接口。

2.当需要本地存储时,使用Serializable 接口。

但Parcelable有个明显的缺点:不能能使用在要将数据存储在磁盘上的情况(如:永久性保 存对象,保存对象的字节序列到本地文件中),因为Parcel本质上为了更好的实现对象在 IPC间传递,并不是一个通用的序列化机制,当改变任何Parcel中数据的底层实现都可能导致之前的数据不可读取,所以此时还是建议使用Serializable 。

二.Serializable接口的使用

Serializable的接口实现很简单,只需让需要序列化的类继承Serializable即可,系统会自动将其序列化。存储时使用FileOutputStream构造一个ObjectOutputStream,使用writeObject 存储对象。读取时使用FileInputStream构造一个ObjectInputStream,使用readObject读取对象。

(一)布局文件activity_main.xml的设计

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
> <EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/main_et_name"
android:hint="你的用户名"
/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/main_et_password"
android:hint="你的密码"
/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/main_et_age"
android:hint="你的年龄"
/> <Button
android:onClick="save"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="保存数据" /> <Button
android:onClick="read"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="读取数据" /> <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="数据"
android:id="@+id/main_tv"
/>
</LinearLayout>
  • 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
  • 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

界面设计:通过几个输入框输入数据,两个按钮一个保存数据一个读取数据,读取的数据显示在一个文本框下。

(二)创建一个属性类继承Serializable

package com.example.lesson18_serializable;
import java.io.Serializable;
/**
*属性类,用来存储数据,继承接口Serializable,但是什么方法都不用重写!
*/
public class People implements Serializable{
//定义基本信息
String name;
String password;
int age;
//无参构造方法
public People() {
super();
}
//有参构造方法,方便数据写入
public People(String name, String password, int age) {
super();
this.name = name;
this.password = password;
this.age = age;
} //重写toString方法,方便显示
@Override
public String toString() {
return "People [name=" + name + ", password=" + password + ", age="
+ age ;
} }
  • 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
  • 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

(三)主方法的类

package com.example.lesson18_serializable;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView; public class MainActivity extends Activity { //保存文件的路径
String path=Environment.getExternalStorageDirectory().getAbsolutePath()+"/people.txt";
//定义布局内的控件
EditText edit_name;
EditText edit_password;
EditText edit_age;
TextView text; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//实例化布局控件
edit_name=(EditText) findViewById(R.id.main_et_name);
edit_password=(EditText) findViewById(R.id.main_et_password);
edit_age=(EditText) findViewById(R.id.main_et_age);
text=(TextView) findViewById(R.id.main_tv);
} //保存数据
public void save(View view){
ObjectOutputStream fos=null;
try { //如果文件不存在就创建文件
File file=new File(path);
//file.createNewFile();
//获取输出流
//这里如果文件不存在会创建文件,这是写文件和读文件不同的地方
fos=new ObjectOutputStream(new FileOutputStream(file));
//获取输入框内的文件进行写入
String name=edit_name.getText().toString();
String password=edit_password.getText().toString();
int age=Integer.parseInt(edit_age.getText().toString());
People people=new People(name, password, age);
//这里不能再用普通的write的方法了
//要使用writeObject
fos.writeObject(people);;
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
if (fos!=null) {
fos.close();
}
} catch (IOException e) {
} } } //读取数据
public void read(View view){
ObjectInputStream ois=null;
try {
Log.e("TAG", new File(path).getAbsolutePath()+"<---");
//获取输入流
ois=new ObjectInputStream(new FileInputStream(new File(path)));
//获取文件中的数据
Object people=ois.readObject();
//把数据显示在TextView中
text.setText(people.toString());
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
if (ois!=null) {
ois.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
} }
  • 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
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 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
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
这里使用但是外部存储的方式来存储数据,需要添加权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  • 1
  • 2
  • 1
  • 2

程序运行后的界面:

输入对应的信息,点击保存,再点击读取显示的结果:

其中这里的数据是保存再本地文件中的,下次不用写入数据,可以直接读取上次写入的文件。

三.Parcelable接口的使用

使用的方法过程要麻烦一些!

实现Parcelable接口主要可以分为一下几步:

1.让属性类Model实现Parcelable接口

2.重写writeToParcel方法,将你的对象序列化为一个Parcel对象,

即:将类的数据写入外部提供的Parcel中,打包需要传递的数据到Parcel容器保存,以便从Parcel容器获取数据。 这里的文件的写入方法非常重要。

3.重写describeContents方法,内容接口描述,默认返回0即可。 这个方法基本没有用!

4.实例化静态内部对象CREATOR实现接口Parcelable.Creator,并重写读取的抽象方法。

这里的读取的方法也是很重要的,必须和写的时候的顺序是一致的。这里的CREATOR接口对象的名字是固定的,如果改成其他名字底层会识别不到这个接口!

注意:若将Parcel看成是一个流,则先通过writeToParcel把对象写到流里面,再通过 createFromParcel从流里读取对象,因此类实现的写入顺序和读出顺序必须一致。

这里设计程序从一个页面跳转到另一个页面,并把对象的数据传递过去。

(一)设计属性类继承Parcelable接口

package com.example.lesson18_parcalable;
import android.os.Parcel;
import android.os.Parcelable;
/**
*属性类,继承Parcelable
*实现两个方法,在其中一个方法内实现对象写入的操作
*创建一个接口类CREATOR,重写读取对象的方法
*/
public class User implements Parcelable{ //User的各种数据的定义
String name;
String password;
int age;
double money;
boolean isAdmin; public User(){} //写一个构造方法来方便写入数据
public User(String name, String password, int age, double money,
boolean isAdmin) {
super();
this.name = name;
this.password = password;
this.age = age;
this.money = money;
this.isAdmin = isAdmin;
} @Override
// 这个方法没什么用
public int describeContents() {
return 0;
} @Override
// 写数据的底层实现
public void writeToParcel(Parcel arg0, int arg1) {
arg0.writeString(name);
arg0.writeString(password);
arg0.writeInt(age);
arg0.writeDouble(money);
//把布尔类型的数据做处理,true1,false0
arg0.writeInt(isAdmin?1:0);
} //实例化静态内部对象CREATOR实现接口,CREATOR名字不能改变,否则会报错
public static Creator CREATOR=new Creator<User>() {
@Override
// 读书数据的底层实现,要和写入的数据的顺序保持一致
public User createFromParcel(Parcel arg0) {
User user=new User();
user.name=arg0.readString();
user.password=arg0.readString();
user.age=arg0.readInt();
user.money=arg0.readDouble();
//布尔类型的数据要处理
user.isAdmin=arg0.readInt()==1?true:false;
return user;
} @Override
public User[] newArray(int arg0) {
//返回
return new User[arg0];
}
}; //从toString方法
@Override
public String toString() {
return "User [name=" + name + ", password=" + password + ", age=" + age
+ ", money=" + money + ", isAdmin=" + isAdmin + "]";
} }
  • 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
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 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
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77

(二)主方法的类的设计

package com.example.lesson18_parcalable;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button; public class MainActivity extends Activity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); Button button=new Button(this);
button.setText("跳转到B页面"); setContentView(button);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
//跳转到另一个页面,对象的数据也要传递过去
Intent intent=new Intent(MainActivity.this,OtherActivity.class);
//定义数据
User user=new User("liwenzhi","123456",22,1000000,true);
//把数据放到Intent对象里面
intent.putExtra("user", user);
//实现页面跳转
startActivity(intent);
}
}); }
}
  • 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
  • 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

上面这个类也是很简单的。设计一个按钮监听跳转到另一个页面。

(三)另一个页面的设计

package com.example.lesson18_parcalable;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView; public class OtherActivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView textView=new TextView(this);
textView.setTextSize(30);
//获取传递过来的数据
User user=getIntent().getParcelableExtra("user");
textView.setText(user.toString());
setContentView(textView); } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

上面的页面也是比较简单的,接收从上一个页面传递过来的对象,然后显示在一个TextView。

程序运行后的显示界面:

点击大按钮后,显示的界面:

上面的数据的写死的,其实也是可以向第一个程序那样使用几个输入框来确定数据的。

对比这两个接口实现的方法和效果:
       对于第一个程序使用Serializable实现了数据的传递,并且数据是保存在本地的,即使是程序被卸载了,其他程序只要是文件路径正确,也可以访问保存的文件的数据,也是可以用来做进程间的通信的,但是这样需要消耗一些内存。
       对比第二个程序使用Parcalable实现了数据的传递,这里的数据是不能保存到本地的,占用的内存较少,比较适合用于进程间的数据传递。
对于应用方面:网络信息传递和进程间数据传递使用Parcalable实现了数据的传递的方式是比较多一点的。
       对于这两种数据传递的信息大小一般不能是很大的数据。

Android序列化的存储和读取的更多相关文章

  1. Android 使用SQLite存储以及读取Drawable对象

    在进行Android开发过程中,我们经常会接触到Drawable对象,那么,若要使用数据库来进行存储及读取,该如何实现? 一.存储 //第一步,将Drawable对象转化为Bitmap对象 Bitma ...

  2. android之文件存储和读取

    一.权限问题 手机中存储空间分为ROM和SDcard,ROM中放着操作系统以及我们安装的APP,而sdcard中一般放置着我们APP产生的数据.当然,Android也为每个APP在ROM中创建一个数据 ...

  3. Android开发之漫漫长途 X——Android序列化

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...

  4. Android本地数据存储: ASimpleCache

    一:前言 在上一篇博客Android本地数据存储: Reservoir 博客中,我提到,除了Reservoir库,还可以采用ASimpleCache开源库,来实现本地数据存储.昨天并没有仔细的对比Re ...

  5. Android中数据存储(一)

    国庆没有给国家添堵,没有勾搭妹子,乖乖的写着自己的博客..... 本文将为大家介绍Android中数据存储的五种方式,数据存储可是非常重要的知识哦. 一,文件存储数据 ①在ROM存储数据 关于在ROM ...

  6. Android使用SharedPreference存储数据

    SharedPreference存储数据和文件存储更加方便的一点是可以按照一定的数据类型进行存储,同时取数据时也能够获取到相应的数据类型.它是按照map的方式来存储和读取数据的. MainActivi ...

  7. 使用 SharedPreferences 实现数据的存储和读取

    在开发的过程中我们必须遇到的就是如何对用户的数据进行有效的存储以及读取.我们举个例子,现在我们使用app,当我们登陆一个账号的时候选择记住密码软件就会记住我们的账号以及密码,我们退出当前账号,就可以直 ...

  8. android学习笔记45——android的数据存储和IO

    android的数据存储和IO SharedPreferences与Editor简介 SharedPreferences保存的数据主要是类似于配置信息格式的数据,因此其保存的数据主要是简单的类型的ke ...

  9. Android实现数据存储技术

    转载:Android实现数据存储技术 本文介绍Android中的5种数据存储方式. 数据存储在开发中是使用最频繁的,在这里主要介绍Android平台中实现数据存储的5种方式,分别是: 1 使用Shar ...

随机推荐

  1. SAS进阶《深入解析SAS》之对多数据集的处理

    SAS进阶<深入解析SAS>之对多数据集的处理 1. 数据集的纵向串接: 数据集的纵向串接指的是,将两个或者多个数据集首尾相连,形成一个新的数据集. 据集的横向合并: 数据集的横向合并,指 ...

  2. CSS——半透明

    1.opacity:不仅背景半透明,内部其他元素也半透明 2.rgba():只有背景半透明. <!DOCTYPE html> <html lang="en"> ...

  3. 【VHDL】组合逻辑电路和时序逻辑电路的区别

    简单的说,组合电路,没有时钟:时序电路,有时钟. ↓ 也就是说,组合逻辑电路没有记忆功能,而时序电路具有记忆功能. ↓ 在VHDL语言中,不完整条件语句对他们二者的影响分别是什么?组合逻辑中可能生成锁 ...

  4. HDU_1532_最大流

    Drainage Ditches Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  5. mysql_基础2

    创建数据表:

  6. centos添加永久的环境变量

    cd /etc/profile.d/ 创建一个sh文件 vi dotnetpath.sh 内容如下: export PATH=$PATH:/opt/dotnet 保存,重启,这就有了一个永久的环境变量

  7. UGUI世界坐标转换为UI本地坐标(游戏Hud的实现)

    实现世界坐标的原理是: 世界坐标和UGUI的坐标分属两个坐标系,他们之间是无法进行转换的,需要通过屏幕坐标系来进行转换(因为屏幕坐标是固定的),即先将游戏场景中的世界坐标通过游戏场景Camera转化为 ...

  8. 想学Python?这里有一个最全面的职位分析

    Python从2015年开始,一直处于火爆的趋势,目前Python工程师超越Java.Web前端等岗位,起薪在15K左右,目前不管是小公司还是知名大公司都在热招中. 当然,每个城市对岗位的需求也不尽相 ...

  9. maxtrid 3D视差

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. c++ map: 当map的value是void*指针

    #include <iostream> #include <map> #include <vector> using namespace std; //key is ...