Androidアプリで画面のデータなどを一時的に保存するなら、オブジェクトにしてごっそり保存するのが便利です。
Serializableインタフェースを実装したクラスのオブジェクトなら、そのままファイルに保存したり、ファイルから読み込んだりできるからです。
アプリイメージ
今回紹介するアプリはこんな感じ。
- 画面に「名前」「電話番号」「メール」を入力できます。
- ボタン「保存」をタップすれば端末内にデータを保存します。
- ボタン「クリア」をタップすれば表示データをクリアします。
- ボタン「読込」をタップすれば、端末内に保存されているデータを読込み、表示します。
アプリ自体は超簡単!ですね。
イメージはわきましたか?
画面データを保持するクラス ViewDto
画面のデータを保持するクラスはこちらになります。
いわゆるDto (Data Transfer Object)ですね。
画面にある「名前」「電話番号」「メール」にあたるインスタンス変数を持っていて、それらのセッターとゲッターがあるだけです。
肝は「Serializable」インタフェースを実装しているところ!
package jp.beourselves.android.sample.storeobjectapp.app; import java.io.Serializable; /** * Created by junchan on 2014/06/05. */ public class ViewDto implements Serializable { private String name; private String tel; private String mail; public ViewDto() { } public ViewDto(String name, String tel, String mail) { this.name = name; this.tel = tel; this.mail = mail; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getTel() { return tel; } public void setTel(String tel) { this.tel = tel; } public String getMail() { return mail; } public void setMail(String mail) { this.mail = mail; } }
このクラスのインスタンスに画面のデータを保持するようにして、
- ボタン「保存」をタップしたら保存
- ボタン「読込」をタップしたら、データを読み込んで、画面に反映
すればいいですね。
メイン画面 MainActivity
メイン画面になります。
このアプリは1画面だけだから、Activityはこれひとつです。
画面のEditTextやボタンの名前は次のようになっていると思ってコードを読んでみてください。
package jp.beourselves.android.sample.storeobjectapp.app; import android.app.Activity; import android.content.Context; import android.support.v7.app.ActionBarActivity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.EditText; import java.io.FileNotFoundException; import java.io.IOException; import java.io.ObjectOutputStream; public class MainActivity extends Activity { /** * 画面のデータを保持するDto */ private ViewDto dto; /** * 「名前」欄 */ private EditText editTextName; /** * 「電話番号」欄 */ private EditText editTextTel; /** * 「メール」欄 */ private EditText editTextMail; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 画面の要素を取得 editTextName = (EditText)findViewById(R.id.editTextName); editTextTel = (EditText)findViewById(R.id.editTextTel); editTextMail = (EditText)findViewById(R.id.editTextMail); // 画面のデータを読み込む load(); } /** * 画面のボタンがタップされた時の処理 * @param view */ public void onClick(View view){ switch (view.getId()){ case R.id.btnStore: // ボタン「保存」がタップされたとき store(); break; case R.id.btnClear: // ボタン「クリア」がタップされたとき clear(); break; case R.id.btnLoad: // ボタン「読込」がタップされたとき load(); break; } } /** * データを書き込む */ private void store(){ // 画面の情報をDtoに詰め込む dto.setName(editTextName.getText().toString()); dto.setTel(editTextTel.getText().toString()); dto.setMail(editTextMail.getText().toString()); // Dtoに詰め込んだデータをファイルに保存する TempDataUtil.store(this, dto); } /** * 画面の入力欄をすべてクリアする */ private void clear(){ dto.setName(""); dto.setTel(""); dto.setMail(""); setDtoToView(); } /** * データを読み込む */ private void load(){ // ファイルに保存したデータを読み込む dto = (ViewDto) TempDataUtil.load(this); // 読み込んだデータを画面に反映する setDtoToView(); } /** * 画面のデータを画面に反映する */ private void setDtoToView(){ editTextName.setText(dto.getName()); editTextTel.setText(dto.getTel()); editTextMail.setText(dto.getMail()); } }
ポイントは、store()メソッドとload()メソッド。
それぞれボタン「保存」、ボタン「読込」をタップしたら呼ばれるようになっています。
ここで画面のデータをViewDtoに格納して端末に保存したり、端末に保存されているデータを読み込んで画面に反映したりします。
肝心のファイルを読み書きする処理は、次のTempDataUtilクラスで行っています。
データの読み書きを行うクラス TempDataUtil
こちらのTempDataUtilで、実際に
- 端末にViewDtoのデータを保存
- 端末のファイルを読み込んで、オブジェクトに格納して返す
をしています。
package jp.beourselves.android.sample.storeobjectapp.app; import android.content.Context; import java.io.FileNotFoundException; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; /** * Created by junchan on 2014/05/27. */ public class TempDataUtil { /** * 保存するファイル名 */ private final static String FILE_NAME = "ViewDto.obj"; /** * データを保存する * @param context * @param object 保存するオブジェクト */ public static void store(Context context, Serializable object){ try { ObjectOutputStream out = new ObjectOutputStream( context.openFileOutput(FILE_NAME, Context.MODE_PRIVATE)); out.writeObject(object); out.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * データを読み込む * @param context * @return 保存しているデータがない場合は null */ public static Object load(Context context){ Object retObj = null; try { ObjectInputStream in = new ObjectInputStream( context.openFileInput(FILE_NAME) ); retObj = in.readObject(); in.close(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return retObj; } }
ポイントを解説していきますね。
ファイル名
ファイル名は最初に定義しています。
/** * 保存するファイル名 */ private final static String FILE_NAME = "ViewDto.obj";
「ViewDto.obj」という名前で保存します。
保存先は、アプリ固有のディレクトリに保存します。
「アプリ固有のディレクトリ」については、次の「ファイルを保存」のところで解説します。
ファイルの保存
ObjectoutputStreamを作って、そのwriteObject()メソッドを使ってオブジェクトを保存しています。
ObjectOutputStream out = new ObjectOutputStream( context.openFileOutput(FILE_NAME, Context.MODE_PRIVATE) ); out.writeObject(object); out.close();
たったこれだけです!
保存先は、
context.openFileOutput(FILE_NAME, Context.MODE_PRIVATE));
で指定しています。
ファイル名は、FILE_NAMEで定義したとおり。
ファイルの保存先のパスは、Context#openFileOutput()メソッドを使うことで、
/data/data/パッケージ名/files/ファイル名
に自動的に指定されます。
このメソッドを使うことで、アプリ固有のディレクトリが指定されるので、開発者がどこに保存するか悩む必要はないです。
実際にファイルが保存されているかは、「Android Device Monitor」などで確認できます。
エミュレータで実行すれば、こんな感じで見ることができます。
実機で実行したときは/dataフォルダ以下が見えないので、工夫が必要です。
参考: Android実機で/data以下のファイルを確認する openFileOutputでファイル作成したらこの方法でチェックしよう
ファイルの読込み
先の「ファイルの保存」で保存したファイルを読込みます。
ObjectInputStreamを作って、そのreadObject()メソッドを使ってオブジェクトを読み込んでいます。
ObjectInputStream in = new ObjectInputStream( context.openFileInput(FILE_NAME) ); retObj = in.readObject(); in.close();
たったこれだけです!
保存の時の逆の操作って感じですよね。
ファイルのパスについては、保存時にアプリ固有のディレクトリを指定しているので、
context.openFileInput(FILE_NAME);
という風に、Context#openFileInput()でファイル名を指定すればOK。
注意点は、readObject()で読み込んだときはObject型になるということ。
使うときはキャストする必要があります。
メイン画面のMainActivityのload()メソッドで、このTempDataUtil#load()を呼んでおり、ViewDto型にキャストして使っています (MainActivityの103行目)
画面のレイアウト
画面レイアウトはかなり適当です。
今回紹介する機能の中では大したことをしているわけでないので、解説の必要もないかなーと思います。
なので、コードだけ紹介しておきますね。
興味があれば見てみてください。
RelativeLayoutにTableLayoutを貼り付けて、その下にボタンを貼り付けています。
そんなに真面目には作っていません (笑
<button>
</button><button>
</button><button>
</button>
おわりに
画面のデータをオブジェクトに格納し、端末内に保存する方法について紹介しました。
データの保存や読込みのコードを見てわかると思いますが、難しいことは何もしていません。
とにかく保存して、とにかく読み込んでいるだけです。
今回紹介した方法では、Serializableを実装したクラスを使っているのがミソです。
Serializableを実装していればStreamに流せるので、読み書きが簡単になるんですね。
これはAndroidだけじゃなくて、普通のJavaプログラムでも同じです。
読み込んでくるときは型がわからないので、ViewDtoにキャストして使っています。
画面のデータを一時的に保存する、という例で紹介しましたが、Serializableを実装したクラスであればどんなものでも同じようにして読み書きできるので、色々な利用の仕方があるのではないでしょうか。
データベースに保存する程でもないのだけれど、一時的に保存しておきたい、といったものだったら、この方法でリーズナブルに保存しちゃうのもアリですよね。
どうぞ、使ってみてください。
元大手電機メーカのシステムエンジニア。
詳しくはこのサイトについての「サイト管理者について」をご覧ください。