序列化
-
为什么要序列化?
- 永久性保存对象,保存对象的 字节序列 到本地文件中
- 通过序列化在网络中传递对象。
- 通过序列化在进程间传递对象。
-
序列化:将数据结构或者对象 state 转换成可以存储的格式(如文件,memory buffer,或者在网络上传输),之后再在相同的计算机或者不同的计算机环境中恢复。当生成的bits序列按serilization 格式被重新读出时,它可以创建一个语义唯一(semantically identical) 的原始对象的克隆。
序列化的过程也被叫做 deflating 或者 marshalling 。相反的操作则叫做 deserialization (也叫做 inflating 或者 unmarshalling )。 -
序列化格式:
- XML , 有常规的xml(human readable text-based encoding,可以用文本编辑器打开) 和 Binary xml。在20世纪,XML经常被用于Ajax网站应用的客户端和服务器之间的数据结构的异步传输。
- JSON, 是一个较之于XML 更加轻量级的序列化格式,JSON 也普遍被用于web 应用的C/S通讯, JSON 基于JavaScript 语法格式,不过也支持其他编程语言。
- YAML, 高效的JSON超集,包括了一些特性使得它拥有更加强大的序列化功能,对人更加友好,拥有更好的潜在兼容性。在看jekyll 时发现了这个: YAML Ain’t Markup Language
- MAC OS X Cocoa..
-
编程语言支持
- Java — java.io.Serializable interface …
- …
参考:wiki百科 Serilization
安卓序列化
- Android 序列化的两种方法
- Serializable 接口
- Parcelable 接口
实现 Parcelable 接口实现安卓序列化
- implemnts Parceable
- 需要序列化的类必须有一个 static field : CREATEOR ( CREATEOR 是一个实现了Parcelable.Creator 接口的对象)
代码示例:
-
目的: 实现 Parcelable 接口用于进程间(?)传递对象。程序的运行流程是: 点击MyParcelable 的button ,启动ActivityB 并将一个Person 实例传递过去,然后再再ActivityB 中将收到的Person 对象的信息显示在Textview 上。
-
主要结构: 一个Project, 建两个Activity— MyParcelable,ActivityB 。 MyParcelable 布局中添加一个button, 为Button 添加属性:
android:onClick=“onClick”
ActivityB 的xml 布局里添加一个TextView。
一个 Person 类实现 Parcelable 接口。 - 代码:
MyParcelable :
public class MyParcelable extends Activity implements OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn1:
Intent intent = new Intent();
intent.setClass(this, ActivityB.class);
Bundle extras = new Bundle();
extras.putParcelable(Person.PARCELABLE_KEY, new Person("Libelosophy", 100));
intent.putExtras(extras);
startActivity(intent);
}
}
}
ActivityB :
public class ActivityB extends Activity {
private TextView tv = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_activity_b);
tv = (TextView) findViewById(R.id.textview);
Person person = getIntent().getExtras().getParcelable(Person.PARCELABLE_KEY);
String person_info = "Name: " + person.getmName()
+ "\n Age: " + person.getmAge();
tv.setText(person_info);
}
}
Person :
public class Person implements Parcelable {
public static final String PARCELABLE_KEY = "PersonParcelableObject";
private String mName;
private int mAge;
public String getmName() {
return mName;
}
public void setmName(String mName) {
this.mName = mName;
}
public int getmAge() {
return mAge;
}
public void setmAge(int mAge) {
this.mAge = mAge;
}
Person(String name, int age) {
setmName(name);
setmAge(age);
}
private Person(Parcel in) {
setmName(in.readString());
setmAge(in.readInt());
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(getmName());
dest.writeInt(getmAge());
}
public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() {
@Override
public Person createFromParcel(Parcel source) {
return new Person(source);
}
@Override
public Person[] newArray(int size) {
return new Person[size];
}
};
}
运行结果: 如预期。
实例
project简单介绍:OIFileManager一个文件浏览器。FileHolder 类包含文件基本信息(文件,扩展名…),FileHolderAdapter 是用来关联View 和 file列表数据的Adapter,FileListFragment 则是界面及执行体。
首先看看FileHolder 里面的代码,FileHolder 实现了 Parcelable 以支持序列化 ,比较熟悉了:
// FileHolder.java 不完整代码
public class FileHolder implements Parcelable, Comparable<FileHolder> {
private File mFile;
private Drawable mIcon;
private String mMimeType = "";
private Context mContext;
private String mExtension;
// 。。。。。。
// 用 Parcel 中保存的对象来够造FileHolder对像 的构造函数
public FileHolder(Parcel in){
mFile = new File(in.readString());
mMimeType = in.readString();
mExtension = in.readString();
}
// 序列化
@Override
public int describeContents() {
return 0;
}
// 可以看见向 Parcel 只写入了三条String : 文件路径, Mimetype, 扩展名
// [可以直接用 dest.writeSerializable() 将mFile写到Parcel] ? [怎么写] : [为什么不这么用]
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mFile.getAbsolutePath());
dest.writeString(mMimeType);
dest.writeString(mExtension);
}
public static final Parcelable.Creator<FileHolder> CREATOR = new Parcelable.Creator<FileHolder>() {
public FileHolder createFromParcel(Parcel in) {
return new FileHolder(in);
}
public FileHolder[] newArray(int size) {
return new FileHolder[size];
}
};
}
在 FileListFragment 中 :
// FileListFragment.java 不完整代码, 函数也被删去了部分代码
private static final String INSTANCE_STATE_PATH = "path";
private static final String INSTANCE_STATE_FILES = "files";
private static final String TAG = "FileListFragment";
File mPreviousDirectory = null;
protected FileHolderListAdapter mAdapter;
protected DirectoryScanner mScanner; //目录扫描器,扫描目录文件列表并将列表作为消息发送的线程
protected ArrayList<FileHolder> mFiles = new ArrayList<FileHolder>();
private String mPath;
private String mFilename;
private ViewFlipper mFlipper;
private File mCurrentDirectory;
// onSaveInstanceState(Bundle) 回调函数用来保存fragment 的state 用于重新构造fragment,
// bundle 所放的state 在函数onCreate , onCreateView onActivityCreate 中可用
// 当然还应该有onViewCreated ,
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(INSTANCE_STATE_PATH, mPath);
// ArrayList 实现了 Serialization 接口, FileHolder 实现了Parcelable 接口。
// Inserts a List of Parcelable values into the mapping of this Bundle
outState.putParcelableArrayList(INSTANCE_STATE_FILES, mFiles); // 就这个调用了。
}
//
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
// 删掉了一些无关 主题的代码
// Get arguments
if (savedInstanceState == null) {
// 如果没有保存过Fragment 的 实例, 则说明是第一次,从启动时的设置参数中取出path 和filename
mPath = getArguments().getString(FileManagerIntents.EXTRA_DIR_PATH);
mFilename = getArguments().getString(
FileManagerIntents.EXTRA_FILENAME);
} else { // 否则直接从保存的bundle 中恢复state
mPath = savedInstanceState.getString(INSTANCE_STATE_PATH);
mFiles = savedInstanceState
.getParcelableArrayList(INSTANCE_STATE_FILES);
}
pathCheckAndFix();
renewScanner();
// 设置数据源,及关联到 Fragment ( ? 一个 ListView 在哪?? )
Log.v(TAG, "设置数据源, FileHolderAdapter关联到 FileListFragment");
mAdapter = new FileHolderListAdapter(mFiles, getActivity());
setListAdapter(mAdapter);
mScanner.start();
}