Android序列化的存储和读取

来源:互联网 发布:mac炉石传说无法运行 编辑:程序博客网 时间:2024/05/16 19:51

       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>

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

(二)创建一个属性类继承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 ;    }}

(三)主方法的类

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();            }        }    }}
这里使用但是外部存储的方式来存储数据,需要添加权限:<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

程序运行后的界面:
c1

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

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

三.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 + "]";    }}

(二)主方法的类的设计

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);            }        });    }}

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

(三)另一个页面的设计

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);    }}

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

程序运行后的显示界面:
c3

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

c4

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

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

3 0
原创粉丝点击