• Android序列化的存储和读取


      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

    程序运行后的界面:
    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 + "]";
        }
    
    }
    • 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。

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

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

    c4

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

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

  • 相关阅读:
    HDU 4358 莫队算法+dfs序+离散化
    HDU 5692 线段树+dfs序
    Codeforces Round #377 (Div. 2) A B C D 水/贪心/贪心/二分
    LVS负载均衡的三种模式和八种算法总结
    hdfs 常用命令
    Linux 系统监控
    CentOS 7 时区设置
    kubernetes 留言版DEMO
    CentOS7 PostgreSQL 主从配置( 三)
    Postgres数据库在Linux中优化
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/7423910.html
Copyright © 2020-2023  润新知