JavaでAndroid Studioアプリ開発を試みるの第7回 「DBヘルパー①」

Android Studio開発の続き。
To Doリストを作成して公開するのを今月の目標にしていたのですが、簡単なものは予定通り完成しました。

作る方に集中しすぎたせいで、こちらの更新を忘れていました。。
データベースの部分が中々上手くいかないのが困りものでした。
ということで、今回はデータベース部分の話です。

Javaでデータベースを使用する理由

メモ帳ファイルで、一時的にであればメモは保管されます。
しかし、アプリを一度終了させて再度開きなおすと、すべて消えています。

次にアプリを開いたときもメモを表示させるには、ファイルに保存しておく必要があります。
純粋にテキストデータとして保存しても良いのですが、特定の条件でデータをピックアップしたりなど後で色々なことをしたくなった時に、データベースとして保存しておくと楽です。

最初のとっかかりとしては面倒なのですが、最初からデータベースを使うことにしておく方がトータルとしては楽という事です。
このデータベースをAndroidで扱うときにSQLiteというSQLを活用するのがお手軽です。
そのため、今回はこのSQLiteを使いたいと思います。

AndroidアプリでデータベースにはDBヘルパーが必要

さて、Android StudioでDBを取り扱う場合でですが、いきなりコードを書き始める前にDB(データベース)ヘルパーというものを用意する必要があります。

データベースを立ち上げて、直接メインプログラムからデータベースを操作するのではなく、DBヘルパーを作って、それを利用してデータベースを操作しましょうというのが流儀です。

MainActivity → DBヘルパーにアクセスを依頼 → データベース

 

こんな感じです。
このDBヘルパーですが、publicなクラスとして作りますので、新しいファイルとして作成します。
publicなクラスは、1つのファイルに1つだけ
さらにファイル名はクラス名.javaにするがJavaのルールですから。

っということで、作成したのが下記のファイルです。
ちょっと、色々やってしまって長くなっているのはご了承ください。

MemoDatabaseHelper.java
public class MemoDatabaseHelper extends SQLiteOpenHelper {

    //定数
    private static final String DATABASE_FILE_NAME = "memo_data.db";
    private static final int DATABASE_VERSION = 1;
    static final String TABLE_NAME = "memo_data";
    static final String ITEM_ID = "_id";
    static final String ITEM_MEMO = "memo"; 
    static final String ITEM_START_DATE = "start_date"; 
    static final String ITEM_COMPLETE_DATE = "complete_date"; 
    static final String ITEM_AUTHOR = "author"; 
    static final String ITEM_CHECKER = "checker"; 
    static final String ITEM_FLAG = "flag"; 
    static final String ITEM_GROUP = "group_name"; 
    static final String ITEM_PRIORITY = "priority"; 

    public MemoDatabaseHelper(@Nullable Context context) {
        super(context, DATABASE_FILE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        StringBuilder sb = new StringBuilder();
        sb.append("CREATE TABLE ");
        sb.append(TABLE_NAME);
        sb.append(" (");
        sb.append(ITEM_ID);
        sb.append(" INTEGER PRIMARY KEY AUTOINCREMENT,");
        sb.append(ITEM_MEMO);
        sb.append(" TEXT, ");
        sb.append(ITEM_START_DATE);
        sb.append(" TEXT, ");
        sb.append(ITEM_COMPLETE_DATE);
        sb.append(" TEXT, ");
        sb.append(ITEM_CHECKER);
        sb.append(" TEXT, ");
        sb.append(ITEM_AUTHOR);
        sb.append(" TEXT, ");
        sb.append(ITEM_FLAG);
        sb.append(" INTEGER, ");
        sb.append(ITEM_GROUP);
        sb.append(" TEXT, ");
        sb.append(ITEM_PRIORITY);
        sb.append(" INTEGER);");
        sqLiteDatabase.execSQL(sb.toString());
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
        StringBuilder sb = new StringBuilder();
        sb.append("DROP TABLE ");
        sb.append(TABLE_NAME);
        sb.append(";");
        sqLiteDatabase.execSQL(sb.toString());
        onCreate(sqLiteDatabase);
    }
}

extends SQLiteOpenHelperの一言で片づける

さて、いきなり長いソースコードが出てきましたが、ざっくりで言うと下記の感じです。

public class MemoDatabaseHelper extends SQLiteOpenHelper {
  *色々定数の定義を記載*
  public MemoDatabaseHelper(@Nullable Context context) {
  }
  @Override
  public void onCreate(SQLiteDatabase sqLiteDatabase) {
  }
  @Override
  public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
  }
}

まず、注目したいのは「extends SQLiteOpenHelper」の部分です。
extendsに関して説明を入れると、今回作ったクラスはSQLiteOpenHelperというクラスの子供ですという意味です。
子供なので親ができることは全てできる上で、クラスファイル内で記載した新たな能力も身に付けられるというわけです。

今回の場合で言うと、SQLiteを使うことにしたので、そのSQLite標準のDBヘルパー共通の部分は自分ではあえて書かず、流用
独自の機能の部分だけ書きますよという事です。

独自の部分って?って感じですが、それが次の話です。

子供クラスの方で上書き必須なメソッド2つ

さて、このextends SQLiteOpenHelperをすると、その子供クラスで必須の記載項目があります。
それが下記の部分です。

  @Override
  public void onCreate(SQLiteDatabase sqLiteDatabase) {
  }
  @Override
  public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
  }

これが何かというと親から「俺が勝手に決めちゃうと困るだろうから、自分のやりやすいように決めてね」と言われているような物です。
中身的には「テーブルの作成 onCreate」と「テーブルの更新 onUpgrade」です。

作りたいプログラムによって、項目の要素や数は違います
だから、テーブルの定義をする部分については、それぞれのプラグラムで書きましょうという事です。

この2つのメソッドを抽象メソッドと言ったりするのですが、つまりは子供のクラスで更新しないとエラーになるという事です。
必ず、中身を作りましょう。
これの中身が無いと、項目がないデータベースになっちゃいますから。。

ちなみに、こっそり書かれている@Overrideですが、書かなくてもエラーになりません。
これの意味は、親で書かれいてるメソッドを上書きしていることを分かり易くしているだけです。
例えば、メソッドの名前を誤記した場合に、この@Overrideを入れておくとそれを教えてくれたりします。

難しい話がまた出てきた、次はコンストラクタ

そして残りが、下記の部分です。

  public MemoDatabaseHelper(@Nullable Context context) {
  }

クラス名と同じ名前のメソッドらしきものです。
これを一般的には「コンストラクタ」って言ったりします。

で、これが何をするのかといえば、クラスが作られるときだけに呼び出されるメソッドです。
具体的な使い方のイメージとしては、人間クラスというクラスがあったとして、その人間に名前と身長と体重という値がついているとします。
この人間の名前や身長、体重などをクラスを作る時の付加情報として入れてもらってもいいのですが、毎回入れるのが面倒。

というような場合に、コンストラクタを使って、何も付加情報が無い場合には名前は「太郎」、身長は「170cm」、体重は「60kg」というような初期値を設定できたりします。
今回のデータベースで言うと、データベースのファイル名とデータベースバージョンをコンストラクタで設定しています。

ぜんぜん進まなかったDBヘルパーの説明

もうちょっと説明ができるかと思ったのですが、寄り道だらけで、今のところDBヘルパーの全体的な構成のみについてしか説明できていません
が!
中身まで説明を始めると長くなりすぎるのでとりあえず今回はこの辺で。。

次回は、全体的な話から細かい部分の話に広げていきたいと思います。
乞うご期待!!

 

JavaでAndroid Studioアプリ開発を試みるの第6回 「ListView」
https://aoi345.com/memorandum/android-studio-listview/

JavaでAndroid Studioアプリ開発を試みるの第6回 「ListView」