【ぶっちゃけAndroidアプリ開発】SQLiteデータベースにアクセスして画面に表示するサンプル

sqliteで作成したテーブルにアクセスして、Activityに表示する簡単なサンプルを作成しました。
動くサンプルコードが欲しい人のために、簡単な解説とともに載せておきます。

Android StudioでEmpty Activityで新規プロジェクト作成し、コピペすれば動くはずです。

＜前提＞
作成日:2020年1月1日
AndroidStudio 3.5.3
targetSdkVersion 26
CompileSdkVersion 29

・Empty Activityの雛形を元に作成。

##1.データベースファイルの作成
```test.csv
1,東京都庁,東京都新宿区西新宿2-8-1,03-5321-1111,metro.tokyo.jp
2,神奈川県庁,神奈川県横浜市中区日本大通1,045-210-1111,pref.kanagawa.jp
3,埼玉県庁,埼玉県さいたま市浦和区高砂3-15-1,048-824-2111,pref.saitama.lg.jp
4,千葉県庁,千葉県千葉市中央市場町1-1,043-223-2110,pref.chiba.lg.jp
5,静岡県庁,静岡県静岡市葵区追手町9-6,054-221-2455,pref.shizuoka.jp
```
・住所録ちっくなcsvファイルをインポートし、sqliteを使用してデータベースファイル「test.db」を作成する。
・テーブル名は「addressbook」、項目は seq(integer),name(text),address(text),phone(text),mail(text) の5つ。
・データベースファイルの作成方法は、[「【ぶっちゃけAndroidアプリ開発】sqliteでデータベースを作成する」](https://qiita.com/Pinehead/items/fa224b936d0faeefe2be)を参照。

##2.データベースファイルをプロジェクトに追加する
###(1)Assetsフォルダの作成
・ツールウィンドウのモジュールを右クリックして、Assetsフォルダを追加する。
<img width="858" alt="スクリーンショット 2020-01-01 12.56.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142654/75cbad0b-99ce-8fa5-1691-ce02c2d09a5e.png">
###(2)データベースファイルの追加
・作成した「test.db」ファイルをAssetsフォルダにコピペする。
<img width="833" alt="スクリーンショット 2020-01-01 17.56.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142654/1ab1717d-0378-4c23-f6bd-b251ba64562c.png">

##3.SQLiteOpenHelperクラスの実装
・SQLiteOpenHelperを継承したクラスを実装する。
・実装例は[「Y.A.M.さんのページ」](http://y-anz-m.blogspot.com/2011/01/android-sqline-database.html)を参照させていただきました。

```DatabaseHelper.java
public class DatabaseHelper extends SQLiteOpenHelper {

    private static String DB_NAME = "test";
    private static String DB_NAME_ASSET = "test.db";
    private static final int DATABASE_VERSION = 1;

    private final Context mContext;
    private final File mDatabasePath;

    public DatabaseHelper(Context context) {
        super(context, DB_NAME, null, DATABASE_VERSION);
        mContext = context;
        mDatabasePath = mContext.getDatabasePath(DB_NAME);
    }

    /**
     * asset に格納したデータベースをコピーするための空のデータベースを作成する
     */
    public void createDatabase() throws IOException {
        boolean dbExist = checkDatabaseExists();

        if (dbExist) {
            // すでにデータベースは作成されている
        } else {
            // このメソッドを呼ぶことで、空のデータベースがアプリのデフォルトシステムパスに作られる
            SQLiteDatabase db = getReadableDatabase();
            db.close();

            try {
                // asset に格納したデータベースをコピーする
                copyDatabaseFromAsset();

                String dbPath = mDatabasePath.getAbsolutePath();
                SQLiteDatabase checkDb = null;
                try {
                    checkDb = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READWRITE);
                } catch (SQLiteException e) {
                }

                if (checkDb != null) {
                    checkDb.setVersion(DATABASE_VERSION);
                    checkDb.close();
                }

            } catch (IOException e) {
                throw new Error("Error copying database");
            }
        }
    }

    /**
     * 再コピーを防止するために、すでにデータベースがあるかどうか判定する
     *
     * @return 存在している場合 {@code true}
     */
    private boolean checkDatabaseExists() {
        String dbPath = mDatabasePath.getAbsolutePath();

        SQLiteDatabase checkDb = null;
        try {
            checkDb = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READONLY);
        } catch (SQLiteException e) {
            // データベースはまだ存在していない
        }

        if (checkDb == null) {
            // データベースはまだ存在していない
            return false;
        }

        int oldVersion = checkDb.getVersion();
        int newVersion = DATABASE_VERSION;

        if (oldVersion == newVersion) {
            // データベースは存在していて最新
            checkDb.close();
            return true;
        }

        // データベースが存在していて最新ではないので削除
        File f = new File(dbPath);
        f.delete();
        return false;
    }

    /**
     * asset に格納したデーだベースをデフォルトのデータベースパスに作成したからのデータベースにコピーする
     */
    private void copyDatabaseFromAsset() throws IOException{

        // asset 内のデータベースファイルにアクセス
        InputStream mInput = mContext.getAssets().open(DB_NAME_ASSET);

        // デフォルトのデータベースパスに作成した空のDB
        OutputStream mOutput = new FileOutputStream(mDatabasePath);

        // コピー
        byte[] buffer = new byte[1024];
        int size;
        while ((size = mInput.read(buffer)) > 0) {
            mOutput.write(buffer, 0, size);
        }

        // Close the streams
        mOutput.flush();
        mOutput.close();
        mInput.close();
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }
}
```
・createDatabaseメソッドでデータベースをプログラムで使用できるようにする。AssetsフォルダのデータベースをAndroid端末内にコピーする。(そうしないと使えないらしい)
##4.MainActivityからデータベースアクセス
```MainActivity.java
public class MainActivity extends AppCompatActivity {

    private DatabaseHelper helper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView textView = findViewById(R.id.textview);

        helper = new DatabaseHelper(this);
        try {
            helper.createDatabase();
        }
        catch (IOException e) {
            throw new Error("Unable to create database");
        }
        StringBuilder builder = new StringBuilder();

        SQLiteDatabase db = helper.getReadableDatabase();
        String sql = "select seq, name, address, phone, mail from addressbook";

        try {
            Cursor cursor = db.rawQuery(sql, null);
            while(cursor.moveToNext()) {
                builder.append(cursor.getInt(0) + " ");
                builder.append(cursor.getString(1) + " ");
                builder.append(cursor.getString(2) + " ");
                builder.append(cursor.getString(3) + " ");
                builder.append(cursor.getString(4) + "\n");
            }
        } finally {
            db.close();
        }
        textView.setText(builder.toString());
    }
}
```
・helperオブジェクトを作成する。
・createDatabaseメソッドでデータベースを使用できる状態にする。
・getReadableDatabaseメソッドで読み取り専用データベースをオープンする。
・sqlで全レコードをselectし、TextViewに表示する。
・このサンプルは読み取り専用だが、getWritableDatabaseで読み書きできるデータベースとしてオープンできる。
##5.レイアウト
```activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">

    <TextView
        android:id="@+id/textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
```
・TextViewのidに「textview」を指定してください。
##6.実行結果
![20200101_173927.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142654/4512d4a0-5246-f1b3-66fe-6699109db781.jpeg)