Android的序列化知识点总结

1. 序列化

在Java中,由于Java程序生成的数据变量都是保存在内存中,一旦程序结束,这些数据也会随之消失。如果想要将它们保存的更久一点,就会用上序列化。Android基于Java,所以概念同理。

具体来说,序列化的作用大体有如下几个:

  • 长时间的保存数据到本地或者磁盘。
  • 不同组件之间进行数据交换。
  • 网络数据交换。

2. 基本用法

  1. 先做一个场景的模拟,假设两个Activity要进行数据交换(通过Intent)。
  2. 在MainActivity中添加一个按钮,再添加一个新的SecondActivity,点击按钮切换到SecondActivity。
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    		
    		// 最基本的切换Activity代码
            Button button = findViewById(R.id.button);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                    startActivity(intent);
                }
            });
                    
    
        }
    }
    
  3. 为了数据交换有一个实体,定义一个User类和User2类,里面就一个id和name以及setter和getter方法且两者内容完全相同。
    public class User {
        private String id;
        private String name;
    
        public void setId(String id) {
            this.id = id;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getId() {
            return id;
        }
    
        public String getName() {
            return name;
        }
    }
    

2.1 Serializable

Java自带的序列化接口,用起来非常简单。

  1. 让目标类implement Serializable,并且新建一个字段serialVersionUID(如何快速新建serialVersionUID看4.1)。
    public class User implements Serializable {
    
    
        private static final long serialVersionUID = -1418746155475547469L;
        
        private String id;
        private String name;
    
        public void setId(String id) {
            this.id = id;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getId() {
            return id;
        }
    
        public String getName() {
            return name;
        }
    }
    
    
  2. 然后就可以直接使用,我们将一个User的数据从MainActivity传到SecondActivity。
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Button button = findViewById(R.id.button);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(MainActivity.this, SecondActivity.class);
    				
                    User user = new User();
                    user.setId("1111");
                    user.setName("2222");
                    intent.putExtra("user", user);
    
                    startActivity(intent);
                }
            });
    
    
        }
    }
    
  3. 再让SecondActivity读取,并且打印到log中(你愿意的话也可以用Toast)
    public class SecondActivity extends AppCompatActivity {
    
        private static final String TAG = "SecondActivity";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_second);
    
            Intent intent = getIntent();
            User user = (User) intent.getSerializableExtra("user");
    
            Log.i(TAG, "onCreate: " + user.getId() + " " + user.getName());
    
        }
    }
    
  4. 结果(有个这个基本用法就很容易举一反三了)。
    在这里插入图片描述

2.2 Parcelable

Parcelable是Android特有的序列化方式,也就是说Parcelable在Java上是用不了的,用法会比Serializable较难一些。

  1. 这回用User2类,先implements Parcelable,再为了消除报错添加相关代码,这些方法的作用我都写在注释中。
  2. 基本上用法比较死板,注意读取和保存的代码书写顺序(参数为Parcel的构造方法和writeToParcel方法)要完全一样即可(比如我保存读取时都是先id再name)。
  3. 一般都是用编译器自动生成相关代码,很省事
    public class User2 implements Parcelable {
    	
    	// 省略了setter和getter方法,实际上还在
        private String id;
        private String name;
    
        /**
         * 从序列化结构中新建对象
         */
        protected User2(Parcel in) {
            id = in.readString();
            name = in.readString();
        }
        
        /**
         * 负责将序列化后的数据再反序列化,得到原先的数据
         */
        public static final Creator<User2> CREATOR = new Creator<User2>() {
            @Override
            public User2 createFromParcel(Parcel in) {
                return new User2(in);
            }
    
            @Override
            public User2[] newArray(int size) {
                return new User2[size];
            }
        };
    
        /**
         * 当前对象的描述,一般都是return 0,有特殊需要的时候才返回别的值
         */
        @Override
        public int describeContents() {
            return 0;
        }
    
        /**
         * 将当前对象写入序列化结构
         */
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeString(id);
            dest.writeString(name);
        }
    }
    
  4. 写入和读取这里不说别的,Intent来说用法完全相同,就是换了个方法名。
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Button button = findViewById(R.id.button);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(MainActivity.this, SecondActivity.class);
    
                    User2 user2 = new User2();
                    user2.setId("3333");
                    user2.setName("4444");
                    intent.putExtra("user2", user2);
    
                    startActivity(intent);
                }
            });
    
    
        }
    }
    
    public class SecondActivity extends AppCompatActivity {
    
        private static final String TAG = "SecondActivity";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_second);
    
            Intent intent = getIntent();
            
            User2 user2 = intent.getParcelableExtra("user2");
            
            Log.i(TAG, "onCreate: " + user2.getId() + " " + user2.getName());
        }
    }
    

在这里插入图片描述

3. Serializable和Parcelable的特点和区别

既然Java已经有Serializable了,那为何Android还要特地再弄一个Parcelable来进行序列化呢。

  • Serializable再Java设计出来的初衷是为了数据的硬盘存储和网络交互,所以Serializable主要是通过IO读写到硬盘上进行序列化,序列化的过程中还用上了反射的技术。
  • Parcelable的设计初衷就是在Android平台上,Serializable的效率太慢,使用Parcelable可以通过内存进行序列化和反序列化,这样在Android平台上,Parcelable的效率就会比Serializable高很多。
  • Serializable在运行时会产生大量的临时变量,容易引起GC。
  • 无论是Serializable还是Parcelable,反序列化后生成的对象都不是同一对象,只是里面的内容相等而已。

所以使用一般如下:

  • 在涉及到硬盘存储和网络连接的时候序列化使用Serializable。
  • 在涉及到不同组件或者不同进程直接通信的时候,使用Parcelable。

4. 其他

4.1 Android Studio如何快速生成serialVersionUID

Windows:

  1. File–>Settings–>Editor–>Inspections–>Java–>Serialization issues–>Serializable class without ‘serialVersionUID’ 勾选中该选项,退出。
  2. 进入实现了Serializable中的类,选中类名(比如正文的User类),Alt+Enter弹出提示,然后直接导入完成。

MAC:

  1. Android Studio–>Preference–>Editor–>Inspections–>Java–>Serialization issues–>Serializable class without ‘serialVersionUID’ 勾选中该选项,退出。
  2. 进入实现了Serializable中的类,选中类名(比如正文的User类),Alt+Enter弹出提示,然后直接导入完成。

4.2 关于serialVersionUID有什么用

它用于判断序列化和反序列化后的类是否是同一个类,通过比较两个值是否相等的方式。如果你没有定义这个值,那么java会根据类生成的class文件自动给出一个serialVersionUID值,如果这个类哪天多了空格,少了一行什么的,给出的值就会改变。这个时候再判断,就会变成不同的类了。所以一般我们都会主动定义一个定值,来避免这种识别错误的情况

4.3 两种序列化的使用率比较低

一般现在的项目中,不怎么会用上Serializable和Parcelable的序列化内容。正常都是用EventBus或LiveData进行不同组件中的通信;网络通信那就是直接用json串了。所以本文的实践意义不大,仅供入门学习。

参考材料

Android序列化总结 - 简书
https://www.jianshu.com/p/208ac4a71c6f
Android中Parcelable的原理和使用方法 - 简书
https://www.jianshu.com/p/df35baa91541

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值