Android Studio初心者がSQLiteを使ってアプリ作成してみた（データの表示、追加）

[ラクスAdvent Calendar2018](https://qiita.com/advent-calendar/2018/rakus)の20日目です。

# はじめに
Android StudioではSQLiteを使いデータのやり取りをすることがあります。この記事では、SQLiteを使って格納したデータを表示する、データを追加する方法を紹介します。

# 過去の記事
Android Studioを触り初めてから過去に作成した記事を紹介します。Android Studioでアプリってそもそもどのように作成するのかを知りたい方やAPIにつないでデータを参照する方法を知りたい方はご覧下さい。

* [Android Studioを使ってHello Worldをやってみた](https://qiita.com/kengo_kuwahara/items/e6a3107870d6e1ec039d)
* [Android Studioで天気情報を表示するアプリを作ってみた
](http://tech-blog.rakus.co.jp/entry/android-studio/weather-hacks)

# SQLiteとは
調べた感じ、作成したアプリ内に組み込める軽量のDBのようなものだそうです。Android Studioでは、ライブラリなどを入れる必要もなく、お手軽に試すことができます。SQLを使うと言えばサーバーを用意してPostgresを用意して...みたいな手順が必要だと思っていた私からすれば、かなりお手軽に使えるDBだという印象です。

* [SQLite公式HP](https://www.sqlite.org/index.html)
* [オープンソースのデータベース／SQLiteとは](https://www.ossnews.jp/oss_info/SQLite)

# 今回作成するアプリ
今回、SQLiteを用いて作成した簡易なアプリの説明をします。
カラオケによく行くので、曲名と得点を記録できるアプリ（仮）を作成しました。

* 初期画面

<img src="https://qiita-image-store.s3.amazonaws.com/0/215981/1ae60095-732f-3e51-a1f4-a2d7a0d58972.png" width=50%>

* 表示ボタンを押したとき
<img src="https://qiita-image-store.s3.amazonaws.com/0/215981/c8dcccd7-2c6e-f6ee-7d2b-0349c6777dc5.png" width=50%>

* データを追加し、表示ボタンを押したとき

![image.png](https://qiita-image-store.s3.amazonaws.com/0/215981/51434ea2-a06c-79b0-f94d-24a679a124b8.png)

# SQLiteOpenHelperの用意
では、ここからこのアプリの作成に必要なことを解説していきます。
まずは、SQLiteを使うために`SQLiteOpenHelper`を継承したクラスを作成します。
`onCreate()`でテーブルを作成し、DBのバージョン（`DATABASE_VERSION`）をあげると `onUpgrade()`で古いテーブルを削除して、新規のテーブルが作成されます。

```java:java
package com.example.karaoke;

import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

/**
 * Created by kuwahara on 2018/09/24.
 * 参考：https://akira-watson.com/android/sqlite.html
 */
public class TestOpenHelper extends SQLiteOpenHelper {

    // データーベースのバージョン
    private static final int DATABASE_VERSION = 3;

    // データーベース情報を変数に格納
    private static final String DATABASE_NAME = "TestDB.db";
    private static final String TABLE_NAME = "testdb";
    private static final String _ID = "_id";
    private static final String COLUMN_NAME_TITLE = "title";
    private static final String COLUMN_NAME_SUBTITLE = "score";

    private static final String SQL_CREATE_ENTRIES =
            "CREATE TABLE " + TABLE_NAME + " (" +
                    _ID + " INTEGER PRIMARY KEY," +
                    COLUMN_NAME_TITLE + " TEXT," +
                    COLUMN_NAME_SUBTITLE + " INTEGER)";

    private static final String SQL_DELETE_ENTRIES =
            "DROP TABLE IF EXISTS " + TABLE_NAME;


    TestOpenHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);

    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(
                SQL_CREATE_ENTRIES
        );

        saveData(db, "music1", 10);
        saveData(db, "music2", 0);
        saveData(db, "music3", 0);
        saveData(db, "music4", 0);
        saveData(db, "music5", 0);

    }

    // 参考：https://sankame.github.io/blog/2017-09-05-android_sqlite_db_upgrade/
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL(
                SQL_DELETE_ENTRIES
        );
        onCreate(db);
    }

    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        onUpgrade(db, oldVersion, newVersion);
    }

    public void saveData(SQLiteDatabase db, String title, int score){
        ContentValues values = new ContentValues();
        values.put("title", title);
        values.put("score", score);

        db.insert("testdb", null, values);
    }
}

```

## （補足）DBのバージョンとupgrade
今回のアプリ作成で、DBのバージョンがイマイチ分からず、詰まったので補足しておきます。
DBのバージョンとは、アプリを起動した際にDBやテーブルの定義を変更する（今回の場合、テーブルをDROPしてCREATEし直す）かを判定するためのパラメータです。
必要もないのにアプリを起動するたび、テーブルをDROPして、CREATEして...みたいなことしていると無駄ですよね。かと言ってDBやテーブルの定義を変えたい起動しても反映されないのは困ります。そこで、DBのバージョンというパラメータを用意しておいて、DBやテーブルを再定義するかを判断しているわけです。

# 表示とデータの追加を実装
次に、データを表示する処理と、追加する処理を実装していきます。

* 表示の処理は、`query()`メソッドを使います。その後は取得した値を結合しています。

```java:java
Cursor cursor = db.query(
                "testdb", // DB名
                new String[] { "title", "score" }, // 取得するカラム名
                null, // WHERE句の列名
                null, // WHERE句の値
                null, // GROUP BY句の値
                null, // HAVING句の値
                null // ORDER BY句の値
        );
```

* データの挿入はContentValueを使い、keyとvalueとして挿入する値を設定し、insertに渡しています。

作成したサンプルコードを下記に示します。

```java:java
package com.example.karaoke;

import android.content.ContentValues;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    private TextView textView;
    private TestOpenHelper helper;

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

        // DB作成
        helper = new TestOpenHelper(getApplicationContext());

        // 変数textViewに表示するテキストビューのidを格納
        textView = findViewById(R.id.text_view);
    }

    /**
     * DBからデータを全件取得し画面に表示する.
     * @param view
     */
    public void readData(View view){
        SQLiteDatabase db = helper.getReadableDatabase();
        Cursor cursor = db.query(
                "testdb",
                new String[] { "title", "score" },
                null,
                null,
                null,
                null,
                null
        );

        cursor.moveToFirst();

        StringBuilder sbuilder = new StringBuilder();

        for (int i = 0; i < cursor.getCount(); i++) {
            sbuilder.append(cursor.getString(0));
            sbuilder.append(":    ");
            sbuilder.append(cursor.getInt(1));
            sbuilder.append("点\n\n");
            cursor.moveToNext();
        }

        cursor.close();

        textView.setText(sbuilder.toString());
    }

    /**
     * データを保存する.
     * @param view
     */
    public void saveData(View view) {
        SQLiteDatabase db = helper.getWritableDatabase();
        ContentValues values = new ContentValues();
        
        EditText editTextTitle = findViewById(R.id.edit_text_key);
        EditText editTextScore = findViewById(R.id.edit_text_value);
        String title = editTextTitle.getText().toString();
        String score = editTextScore.getText().toString();
        values.put("title", title);
        values.put("score", score);

        db.insert("testdb", null, values);
    }
}
```

# おわりに
今回はSQLiteを使ったAndroidアプリを紹介しました。
最初はDBバージョンがイマイチ理解できず悩みましたが、サーバーを用意せずとも簡単に（アプリ内で完結して）DB操作ができるため「これは使える!」という印象です。まだデータの検索や削除ができない状態なので、今後追加していきたいと思います。

明日は[kawanamiyuu](https://qiita.com/kawanamiyuu)さんの記事です。どうぞお楽しみに。