4. Android学習 メモ帳アプリ開発

**勉強できること**
LinearLayoutの使い方
ListViewの使い方
ファイル保存

**環境**
AndroidStudioのバージョン：4.0.1
言語：Java

# メモ帳アプリを作ろう

ざっくり設計：
メモ内容を入力し、入力したメモを一覧表示する
メモの内容を保存する
エディタの内容を削除する

イメージ図：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/718108/b82b4a71-a314-5ddc-5c61-3b6c22a89284.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/718108/f46b8f27-a936-01f1-04cb-61242bf4dbe3.png)

早速作っていきます。
まずxmlに、
メモ内容を入力するためのEditText
メモ内容を保存、消すためのButton
メモ内容を一覧表示するListView
を定義していきます。

```xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <!--メモ内容を入力するためのViewです-->
    <EditText
        android:id="@+id/edit_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <!-- 保存するボタン、内容を消すボタンは横並びなので -->
    <!-- LinearLayoutを入れ子にして、layout_weightを使って均等割り付けにして実現します -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        >

        <!--メモ内容を保存するためのButtonです-->
        <Button
            android:id="@+id/save_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="保存する"
            />

        <!--メモ内容を消すためのButtonです-->
        <Button
            android:id="@+id/clear_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="内容を消す"
            />
    </LinearLayout>

    <!--メモ内容一覧表示するViewです-->
    <ListView
        android:id="@+id/memo_list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</LinearLayout>
```

次にActivityに
ボタンクリック時の処理、リストにメモ内容を反映させる処理を書いていきます。
ListViewはAdapterを使ってリストを追加していきます。

```java
package com.example.memoapp;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    ArrayAdapter <String> adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final EditText editText = (EditText)findViewById(R.id.edit_text);
        Button saveButton = (Button)findViewById(R.id.save_button);
        Button clearButton = (Button)findViewById(R.id.clear_button);
        ListView listView = (ListView)findViewById(R.id.memo_list);

        // ListViewに対してアイテムを動的に追加していく場合はadapterを利用します
        // simple_list_item_1 はデフォルトで提供されているTextViewのみ持つレイアウトです。
        // 自作したLayoutを指定して複雑なリストも作成可能です。
        adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1);
        listView.setAdapter(adapter);

        // 保存ボタンをタップ時の処理
        saveButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // エディタの内容を取得します
                String memo = editText.getText().toString();

                // メモ内容が入力されていない場合は保存しないようにします
                if (memo.isEmpty()) {
                    // Toastを使ってメッセージを表示します
                    Toast.makeText(getApplicationContext(), "メモ内容が入力されていません", Toast.LENGTH_SHORT).show();
                    return;
                }

                // リストにメモ内容を反映します
                adapter.add(memo);

                // エディタはクリアします
                editText.setText("");
            }
        });

        // 消すボタンをタップ時の処理
        clearButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // エディタに空文字をセットします
                editText.setText("");
            }
        });
    }
}
```

実行すると、このような感じになっているかと思います。

![Screenshot_20201223-220944.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/718108/1cc0ad35-e767-a623-81d4-825cfcfd3c4a.png)

ですがこのままだとアプリを一度終了すると、メモ内容が保存されず、
メモ内容が消えてしまうので、保存する機能をつけていきます。

Androidではデータの保存方法が3つあります。

| 保存方法 | 詳細 |
|:--|:--|
|Shared Preferences|設定値などを保存するときに利用します。|
|ファイル保存|ファイルに書き込むことでデータを保存します。|
|SQLite DB|Androidで用意されているDBです。|

今回はファイルにデータを保存する方法をとります。
BufferedReader、BufferedWriterを使ってファイルの書き込み、読み込み処理を実装します。


```java
    private String fileName = "memo.txt";
    private String splitStr = "///";

    // 保存されているメモを取得する
    private String[] readMemo() {
        BufferedReader reader = null;
        String memoTxt = "";
        try {
            reader = new BufferedReader(new InputStreamReader(openFileInput(fileName)));
            String str;
            while((str = reader.readLine()) != null) {
                memoTxt = memoTxt + str;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(reader != null) {
                    reader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        // メモが保存されていない場合はnullを返す
        if (memoTxt == "") {
            return null;
        }

        // 区切り文字で区切って返す
        return memoTxt.split(splitStr);
    }

    // メモを端末に保存する
    private void saveMemo(String str) {
        BufferedWriter writer = null;
        try {
            writer = new BufferedWriter(new OutputStreamWriter(openFileOutput(fileName, Context.MODE_PRIVATE)));
            writer.write(str);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(writer != null) {
                    writer.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
```

Activityファイル自体はこのようになります。

```java
package com.example.memoapp;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class MainActivity extends AppCompatActivity {

    ArrayAdapter <String> adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final EditText editText = (EditText)findViewById(R.id.edit_text);
        Button saveButton = (Button)findViewById(R.id.save_button);
        Button clearButton = (Button)findViewById(R.id.clear_button);
        final ListView listView = (ListView)findViewById(R.id.memo_list);

        // ListViewに対してアイテムを動的に追加していく場合はadapterを利用します
        // simple_list_item_1 はデフォルトで提供されているTextViewのみ持つレイアウトです。
        // 自作したLayoutを指定して複雑なリストも作成可能です。
        adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1);
        listView.setAdapter(adapter);

        // 保存済みのメモがあれば読み込む
        String[] saveMemoList = readMemo();
        if (saveMemoList != null) {
            adapter.addAll(saveMemoList);
        }

        // 保存ボタンをタップ時の処理
        saveButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // エディタの内容を取得します
                String memo = editText.getText().toString();

                // メモ内容が入力されていない場合は保存しないようにします
                if (memo.isEmpty()) {
                    // Toastを使ってメッセージを表示します
                    Toast.makeText(getApplicationContext(), "メモ内容が入力されていません", Toast.LENGTH_SHORT).show();
                    return;
                }

                // リストにメモ内容を反映します
                adapter.add(memo);

                // エディタはクリアします
                editText.setText("");

                // メモの内容を保存します
                String memoTmp = "";
                for (int i = 0; i < adapter.getCount(); i++) {
                    memoTmp += adapter.getItem(i) + splitStr;
                }
                saveMemo(memoTmp.substring(0, memoTmp.length() - splitStr.length()));
            }
        });

        // 消すボタンをタップ時の処理
        clearButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // エディタに空文字をセットします
                editText.setText("");
            }
        });
    }

    private String fileName = "memo.txt";
    private String splitStr = "///";

    // 保存されているメモを取得する
    private String[] readMemo() {
        BufferedReader reader = null;
        String memoTxt = "";
        try {
            reader = new BufferedReader(new InputStreamReader(openFileInput(fileName)));
            String str;
            while((str = reader.readLine()) != null) {
                memoTxt = memoTxt + str;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(reader != null) {
                    reader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        // メモが保存されていない場合はnullを返す
        if (memoTxt == "") {
            return null;
        }

        // 区切り文字で区切って返す
        return memoTxt.split(splitStr);
    }

    // メモを端末に保存する
    private void saveMemo(String str) {
        BufferedWriter writer = null;
        try {
            writer = new BufferedWriter(new OutputStreamWriter(openFileOutput(fileName, Context.MODE_PRIVATE)));
            writer.write(str);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(writer != null) {
                    writer.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
```

メモを書いて、一覧に反映し、保存するメモアプリができました。
メモアプリは一覧のメモの削除や編集機能、保存日時の表示など様々な機能があると
より便利になるので色々試してみてください。