版权声明:本文为HaiyuKing原创文章,转载请注明出处!
前言
简单记录下序列化Serializable和Parcelable的使用方法。
Android中Intent如果要传递类对象,可以通过两种方式实现
- 方式一:Serializable,要传递的类实现Serializable接口传递对象,
- 方式二:Parcelable,要传递的类实现Parcelable接口传递对象。
Serializable(Java自带):
Serializable是序列化的意思,表示将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络上进行传输,也可以存储到本地。
Parcelable(android 专用):
除了Serializable之外,使用Parcelable也可以实现相同的效果,
不过不同于将对象进行序列化,Parcelable方式的实现原理是将一个完整的对象进行分解,
而分解后的每一部分都是Intent所支持的数据类型,这样也就实现传递对象的功能了。
实现序列化的作用
1)永久性保存对象,保存对象的字节序列到本地文件中;
2)通过序列化对象在网络中传递对象;
3)通过序列化在进程间传递对象。
选择序列化方法的原则
1)在使用内存的时候,Parcelable比Serializable性能高,所以推荐使用Parcelable。
2)Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC。
3)Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable不能很好的保证数据的持续性在外界有变化的情况下。尽管Serializable效率低点,但此时还是建议使用Serializable 。
使用方法
新建bean类
1、新建bean类implement Parcelable,重写以下方法
在Android Studio中可以自动引入:
package com.why.project.androidcnblogsdemo.bean; import android.os.Parcel; import android.os.Parcelable; /** * Created by HaiyuKing * Used 用户bean类 */ public class UserBean implements Parcelable{ private String userName; private int userId; private boolean isVip; //必须要添加 public UserBean(){} public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } public boolean isVip() { return isVip; } public void setVip(boolean vip) { isVip = vip; } //默认返回0就可以 //返回当前对象的内容描述,如果含有文件描述符,返回1,否则返回0,几乎所有情况都返回0 @Override public int describeContents() { return 0; } //将你的对象序列化为一个Parcel对象 即:将类的数据写入外部提供的Parcel中,打包需要传递的数据到Parcel容器保存,以便从 Parcel容器获取数据 //将当前对象写入序列化结构中,其中flags标识有两种值:0或者1,为1时标识当前对象需要作为返回值返回,不能立即释放资源,几乎所有情况都为0 @Override public void writeToParcel(Parcel parcel, int i) { parcel.writeString(userName); parcel.writeInt(userId); parcel.writeByte((byte) (isVip ? 1 : 0)); } public static final Creator<UserBean> CREATOR = new Creator<UserBean>() { //从序列化后的对象中创建原始对象 @Override public UserBean createFromParcel(Parcel in) { return new UserBean(in); } //创建指定长度的原始对象数组 @Override public UserBean[] newArray(int size) { return new UserBean[size]; } }; //从序列化后的对象中创建原始对象 protected UserBean(Parcel in) { userName = in.readString(); userId = in.readInt(); isVip = in.readByte() != 0; } }
2、新建bean类implement Serializable,手动指定serialVersionUID的值
不指定serialVersionUID也可以实现序列化,但是应该指定。这个serialVersionUID是用来辅助序列化和反序列化过程的,原则上序列化后的数据中的serialVersionUID只有和当前类的serialVersionUID相同才能够正常地被反序列化。serialVersionUID的详细工作机制是这样的:序列化的时候系统会将当前类的serialVersionUID写入序列化的文件中(也可能是其他中介),当反序列化的时候系统会检测文件中的serialVersionUID,看它是否和当前类的serialVersionUID一致,如果一致就说明序列化的类的版本和当前类的版本是相同的,这个时候可以成功反序列化;否则就说明当前类和序列化的类相比发生了某些变化,比如成员变量的数量、类型可能发生了改变,这个时候是无法正常反序列化的,因此会报错
而手动指定serialVersionUID值的话,序列化和反序列化时两者的serialVersionUID是相同的。如果不手动指定serialVersionUID的值,反序列化时当前类发生了改变,比如增加或者删除成员变量,那么系统就会重新计算当前类的hash值并把赋值给serialVersionUID,这个时候当前类的serialVersionUID就和序列化数据中的serialVersionUID不一致,于是反序列化失败。
--摘自《Android开发艺术探索》
package com.why.project.androidcnblogsdemo.bean; import java.io.Serializable; /** * Created by HaiyuKing * Used 书籍Bean类 */ public class BookBean implements Serializable { private static final long serialVersionUID = 123L;//手动指定值,默认是1L,可以是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段 private String bookName; private float bookPrice; public String getBookName() { return bookName; } public void setBookName(String bookName) { this.bookName = bookName; } public float getBookPrice() { return bookPrice; } public void setBookPrice(float bookPrice) { this.bookPrice = bookPrice; } }
(1)通过序列化在进程间传递对象【使用Parcelable】
顺带演示Serializable的使用方法。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <Button android:id="@+id/btn_intent" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="通过序列化在进程间传递对象" android:layout_margin="10dp"/> <Button android:id="@+id/btn_savefile" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="保存对象的字节序列到本地文件中" android:layout_margin="10dp"/> <Button android:id="@+id/btn_openfile" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="反序列化从文件中读取对象数据" android:layout_margin="10dp"/> <TextView android:id="@+id/tv_showbookInfo" android:layout_width="match_parent" android:layout_height="wrap_content"/> </LinearLayout>
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="通过序列化Parcelable传递的对象数据"/> <TextView android:id="@+id/tv_Parcelable" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="10dp"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="通过序列化Serializable传递的对象数据"/> <TextView android:id="@+id/tv_Serializable" android:layout_width="match_parent" android:layout_height="wrap_content"/> </LinearLayout>
package com.why.project.androidcnblogsdemo.activity; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.TextView; import com.why.project.androidcnblogsdemo.R; import com.why.project.androidcnblogsdemo.bean.BookBean; import com.why.project.androidcnblogsdemo.bean.UserBean; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; /** * Created by HaiyuKing * Used 序列化的首页界面 */ public class SerializeOneActivity extends AppCompatActivity{ private UserBean mUserBean; private BookBean mBookBean; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_serialize_one); initDatas(); initEvents(); } private void initDatas() { mUserBean = new UserBean(); mUserBean.setUserId(1111); mUserBean.setUserName("haiyuKing"); mUserBean.setVip(true); mBookBean = new BookBean(); mBookBean.setBookName("Android开发艺术探索"); mBookBean.setBookPrice(79f); } private void initEvents() { findViewById(R.id.btn_intent).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(SerializeOneActivity.this, SerializeTwoActivity.class); Bundle bundle = new Bundle(); bundle.putParcelable("bundle_user",mUserBean); bundle.putSerializable("bundle_book",mBookBean); intent.putExtras(bundle); startActivity(intent); } }); findViewById(R.id.btn_savefile).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { } }); findViewById(R.id.btn_openfile).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { } }); } }
接收:
package com.why.project.androidcnblogsdemo.activity; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.widget.TextView; import com.why.project.androidcnblogsdemo.R; import com.why.project.androidcnblogsdemo.bean.BookBean; import com.why.project.androidcnblogsdemo.bean.UserBean; /** * Created by HaiyuKing * Used 序列化的第二个界面 */ public class SerializeTwoActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_serialize_two); TextView tv_Parcelable = findViewById(R.id.tv_Parcelable); TextView tv_Serializable = findViewById(R.id.tv_Serializable); UserBean userBean = (UserBean)getIntent().getParcelableExtra("bundle_user"); BookBean bookBean = (BookBean)getIntent().getSerializableExtra("bundle_book"); tv_Parcelable.setText(userBean.getUserId()+";"+userBean.getUserName()+";"+userBean.isVip()); tv_Serializable.setText(bookBean.getBookName()+";"+bookBean.getBookPrice()); } }
效果图
(2)保存对象的字节序列到本地文件中【使用Serializable】
package com.why.project.androidcnblogsdemo.activity; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.TextView; import com.why.project.androidcnblogsdemo.R; import com.why.project.androidcnblogsdemo.bean.BookBean; import com.why.project.androidcnblogsdemo.bean.UserBean; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; /** * Created by HaiyuKing * Used 序列化的首页界面 */ public class SerializeOneActivity extends AppCompatActivity{ private UserBean mUserBean; private BookBean mBookBean; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_serialize_one); initDatas(); initEvents(); } private void initDatas() { mUserBean = new UserBean(); mUserBean.setUserId(1111); mUserBean.setUserName("haiyuKing"); mUserBean.setVip(true); mBookBean = new BookBean(); mBookBean.setBookName("Android开发艺术探索"); mBookBean.setBookPrice(79f); } private void initEvents() { findViewById(R.id.btn_intent).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { } }); findViewById(R.id.btn_savefile).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { try { //文件存放的位置在 /data/data/<package>/files 下 File file = new File(SerializeOneActivity.this.getFilesDir().getPath(), "cache.txt"); ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file)); out.writeObject(mBookBean); out.close(); } catch (IOException e) { e.printStackTrace(); } } }); findViewById(R.id.btn_openfile).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { try { //文件存放的位置在 /data/data/<package>/files 下 File file = new File(SerializeOneActivity.this.getFilesDir().getPath(), "cache.txt"); ObjectInputStream out = new ObjectInputStream(new FileInputStream(file)); BookBean newBookBean = (BookBean) out.readObject();//内容一致,但不是同一个对象 out.close(); TextView tv_showbookInfo = findViewById(R.id.tv_showbookInfo); tv_showbookInfo.setText(newBookBean.getBookName()+";"+newBookBean.getBookPrice()); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }); } }
cache.txt的路径:
效果图:
(3)将对象序列化后通过网络传输【使用Serializable】
暂时空缺
参考资料
序列化Serializable和Parcelable的理解和区别
《Android开发艺术探索》