今回はAndroidに特化した話ではなく、Javaについての話です。
データ用のクラスを用意し、複数のフィールドに値を入れて管理するという方法を取ることがあるかと思います。この場合、Preferenceを使う方法でフィールドを1つずつ保存していくということも考えられますが、データのオブジェクトごと保存ができると復元の時も含めて手軽に行うことができますね。
今回は、オブジェクトをシリアライズ(直列化)してファイルに保存、ファイルから読み込みする方法を説明したいと思います。
java.io.Serializableインタフェース
オブジェクトをシリアライズ可能にするには、そのクラスがjava.io.Serializableインタフェース(以下、Serializableインタフェース)を実装する必要があります。
public class HogeClass implements Serializable
Serializableインタフェースはメソッド、フィールドがなく、シリアライズが可能であるという意味を識別する機能だけを備えています。
ですので、上記の例のように implements Serializable とだけ記述すれば、他にメソッドを実装するなどの手間は必要ありません。
ただし、注意事項があります。クラス内のフィールドはプリミティブ型(intやboolean)か、もしくはシリアライズ可能なクラスでなければなりません。
シリアルバージョンID
シリアライズ、デシリアライズの前後で、クラスのバージョンが異なっていないかを識別する為にserialVersionUIDを定義します。定義しなくても動作しますが、定義しておくと万が一シリアライズした時から、デシリアライズまでにクラスの中身が変更されていた場合に例外を発生させてくれます。
private static final long serialVersionUID = 6255752248513019027L;
serialVersionUIDが定義されていないと警告を出します。
Eclipseですと、この場合にシリアルバージョンIDを生成させることも可能です。
「生成シリアル・バージョンIDの追加」を選択すると自動で計算して定義を追加してくれます。
今回は例としてStringクラスとintを1つずつフィールドに持つクラス、SerializableDataを用意してみました。それぞれのフィールドのGetterとSetterだけを持つシンプルなクラスです。
package org.jpn.techbooster.sample; import java.io.Serializable; public class SerializableData implements Serializable { private static final long serialVersionUID = 6255752248513019027L; private String string_; private int number_; public String getString() { return string_; } public void setString(String string) { string_ = string; } public int getNumber() { return number_; } public void setNumber(int number) { number_ = number; } }
ObjectOutputStream、ObjectInputStream
シリアライズ可能なクラスを用意したところで、次は実際にどのようにファイルに保存するのかを説明します。
そこで登場するのがObjectOutputStreamクラスとObjectInputStreamクラスです。
ObjectOutputStreamのコンストラクタは ObjectOutputStream(OutputStream out) です。今回はファイルに書き込みたいのでFileOutputStreamを指定します。
そして、writeObjectメソッドの引数にシリアライズ可能なオブジェクトを与えることでObjectOutputStreamクラスは指定されたオブジェクトをシリアライズしてストリームにアウトプットします。
以下の例では二つのEditTextに入力されている値を取得してSerializableDataのフィールドに設定、そしてSaveData.datというファイル名で保存するソースです。
SerializableData data = new SerializableData(); data.setString(editTextString_.getText().toString()); data.setNumber(Integer.parseInt(editTextNumber_.getText().toString())); try { FileOutputStream fos = openFileOutput("SaveData.dat", MODE_PRIVATE); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(data); oos.close(); } catch (Exception e) { Log.d(TAG, "Error"); }
逆にデシリアライズする場合はObjectInputStreamクラスを使います。コンストラクタの引数にFileInputStreamを指定し、readObjectメソッドで読み込みます。
try { FileInputStream fis = openFileInput("SaveData.dat"); ObjectInputStream ois = new ObjectInputStream(fis); SerializableData data = (SerializableData) ois.readObject(); ois.close(); } catch (Exception e) { Log.d(TAG, "Error"); }