前回はファイルに対してテキストの書き込みを行ったが、オブジェクトを直接書き込むこともできる。今回はまずその方法を学ぼう。

●ステップ1
ファイルに書き込みたいクラスにSerializableインターフェイスを実装する。

import java.io.Serializable;
public class Word implements Serializable {

    private String word;
    private String body;

    public Word(String word, String body) {
        this.word = word;
        this.body = body;
    }

    @Override
    public String toString() {
        return "word:" + word + " body:" + body;
    }
    
}

●ステップ2
読み込みはfisをObjectInputStreamで包み、readObject()
書き込みはfosをObjectOutputStreamで包み,writeObject(Object)
詳しくは以下のソースコードを参照せよ。
以下のソースコードではWordクラスのインスタンスをファイルに書き込み、その書き込まれたファイルから復元する手順を示している。

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ObjectInputStream ois=null;
        ObjectOutputStream oos=null;
        try {
            //書き込みストリームにファイルを指定
            FileOutputStream fos=openFileOutput("data.dat",MODE_PRIVATE);
            //シリアライズ
            oos= new ObjectOutputStream(fos);
            //Wordインスタンスを書き込み
            oos.writeObject(new Word("word1","body1"));

            //読み込みストリームにファイルを指定
            FileInputStream fis=openFileInput("data.dat");
            //デシリアライズ
            ois=new ObjectInputStream(fis);
            //readObjectはオブジェクト型なのでダウンキャスト
            Word w=(Word)ois.readObject();
            //トースト表示
            Toast.makeText(this,w.toString(),Toast.LENGTH_SHORT).show();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }finally{
            try{
                if(ois != null){ois.close();}
                if(oos != null){oos.close();}
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }
}

オブジェクトのファイルへ書き込み方法がわかったところで前回のお題をListを直接ファイルに書く方法で実現してみよう。StringクラスもArrayListクラスもSerializableインターフェイスを実装しているので特別な処理をせずに上記の方法で読み書きできる。

Q1
登録されているデータ(List)をファイルに書き込み、次回起動時に復元させよ。
なお、今回はObjectOutputStreamクラスとObjectInputStreamクラスを使ってオブジェクトを直接ファイルに記録すること。
書き込み処理は
アプリがバックグランドにまわる際のonPauseをオーバーライドしてそこに書くとよい。

[実行例]

スタート画面
リストアイテムを登録するフォームとボタンがある。

フォームに入力し登録ボタンを押すと・・・

フォーム下部にあるリストビューに表示される。

いくつか登録する。

リストアイテム長押しでアイテムを削除できる。
下図はitem2を削除した。

バックボタンを押してアプリを終了する。

アプリ一覧からアプリを再起動する。

データが復元されていることが確認できる。

●activity_main.xml


<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <ListView
        android:id="@+id/lv"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginTop="8dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/etItem"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginBottom="8dp" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="item"
        android:layout_marginLeft="8dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintBaseline_toBaselineOf="@+id/etItem" />

    <EditText
        android:id="@+id/etItem"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:ems="10"
        android:inputType="textPersonName"
        app:layout_constraintLeft_toRightOf="@+id/textView"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginTop="8dp"
        android:onClick="btClick"
        android:text="登録"
        app:layout_constraintLeft_toRightOf="@+id/etItem"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>



●MainActivity.java

package com.example.mjpurin.filesaveobject;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private ListView lv;
    private EditText etItem;
    private List<String> list=new ArrayList<>();
    private ArrayAdapter<String> adapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //ファイル未作成の場合はnullが帰る
        Object ret=readFile();
        if(ret != null){
            list=(List<String>)ret;
        }
        lv=(ListView)findViewById(R.id.lv);
        etItem=(EditText)findViewById(R.id.etItem);
        adapter=new ArrayAdapter<>(this,android.R.layout.simple_list_item_1,list);
        lv.setAdapter(adapter);
        lv.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                list.remove(position);
                adapter.notifyDataSetChanged();
                Toast.makeText(MainActivity.this,"削除しました。",Toast.LENGTH_SHORT).show();
                return true;
            }
        });

    }
    public void btClick(View v){
        String item=etItem.getText().toString();
        list.add(item);
        adapter.notifyDataSetChanged();
        etItem.setText("");
    }
    //ファイルを読み込みオブジェクトを返却
    private Object readFile() {
        //返却するオブジェクト(初期値null)
        Object ret=null;
        //ObjectInputStream型の変数を宣言
        ObjectInputStream ois=null;
        try {
            //fisを作成
            FileInputStream fis=openFileInput("data.dat");
            //fisをラッピングする形でObjectInputStreamインスタンスを作成
            ois=new ObjectInputStream(fis);
            //oisがreadObjectをするとオブジェクトを取得できる(Object型)
            ret=ois.readObject();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally{
            if(ois !=null){
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return ret;

    }

    @Override
    protected void onPause() {
        super.onPause();
        //ObjectOutputStream型の変数を宣言
        ObjectOutputStream oos=null;
        try {
            //fosを作成
            FileOutputStream fos=openFileOutput("data.dat",MODE_PRIVATE);
            //fosをラッピングする形でObjectOutputStreamインスタンスを作成
            oos=new ObjectOutputStream(fos);
            //oosがwriteObject(object)でobjectをファイルに書き込める
            //今回はArrayListをそのまま書き込む
            oos.writeObject(list);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            if(oos != null){
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}