Androidデバイスでローカル(Androidデバイス内)にデータベースを構築する

この記事はAndroidデバイス内にSQLiteを用いて`mydatabase.db`としてファイル形式でデータベースを実装する方法について説明する．
>API通信を実装してリモートでデータベースにアクセスする方法については以下の記事を参照すること．
>https://qiita.com/tarakokko3233/items/0961933e2b9695cb561a

>**SQLiteとは**
>軽量でサーバーレスの関係データベース管理システム（RDBMS）のこと．SQLiteはサーバーを必要とせず，モバイルアプリ，デスクトップアプリ、ブラウザ拡張機能など，幅広い用途に組み込むことができる．

## 1．AndroidStudioでアプリケーションプロジェクトを作成
AndroidStudioを開き，以下のようにプロジェクトを作成する．今回はJavaを用いて以下のようにプロジェクト名とパッケージ名とSDKのバージョンを指定した．
>このPackage nameは後でデータベースファイルにアクセスする際に必要なので覚えておくこと．

![スクリーンショット 2024-04-19 12.01.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3757442/e3002ff8-2ac0-f60b-a6e7-6bc84791f82e.png)
## 2．レイアウト作成
`app/res/layout/activity_main.xml`にレイアウトXMLファイルを作成する．
![スクリーンショット 2024-04-19 14.05.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3757442/ba521fda-dd61-c3d1-0a91-20baaa865db1.png)


とりあえずデータベースファイル内のテーブルをリスト表示するだけの簡単なレイアウトを作成する．
```activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ListView
        android:id="@+id/userListView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

```

## 3．データベース構築
`app/java/com.example.myapplication`にデータベースを構築する用のJavaファイルを生成していく．
![スクリーンショット 2024-04-19 13.34.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3757442/76b6cec7-a570-c52f-5155-13664fe1aa15.png)

### 1.User.java
Userテーブルのモデルを定義する．
```User.java
package com.example.myapplication;

public class User {
    private int id;
    private String name;
    private String email;

    public User(int id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }

    //idを取得するメソッド
    public int getId() {
        return id;
    }

    //nameを取得するメソッド
    public String getName() {
        return name;
    }

    //emailを取得するメソッド
    public String getEmail() {
        return email;
    }

    //idを更新するメソッド
    public void setId(int id) {
        this.id = id;
    }

    //setName(),setEmail()
}


```

### 2.UserAdapter.java
BaseAdapterを継承したカスタムアダプター．UserオブジェクトのリストをXMLでListViewに表示するために使用される．activity_main.xmlにListViewを定義したのでその中のTextViewにsetTextでUser.javaで作成したゲッターメソッドを使用して画面上に表示する．
```UserAdapter.java
package com.example.myapplication;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import java.util.List;

public class UserAdapter extends BaseAdapter {

    private Context context;
    private List<User> users;

    public UserAdapter(Context context, List<User> users) {
        this.context = context;
        this.users = users;
    }
    // アダプターが管理するアイテムの数や，指定された位置のアイテムを返す．
    @Override
    public int getCount() {
        return users.size();
    }

    @Override
    public User getItem(int position) {
        return users.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    //指定された位置のアイテムのビューを返す
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_2, parent, false);
        }

        User user = getItem(position);
        TextView text1 = convertView.findViewById(android.R.id.text1);
        TextView text2 = convertView.findViewById(android.R.id.text2);
        text1.setText(user.getName());
        text2.setText(user.getEmail());

        return convertView;
    }
}
```
### 3.DatabaseHelper.java
SQLiteOpenHelperを継承したヘルパークラスで，SQLiteデータベースの作成，バージョン管理，データの取得などの操作を行うために使用される．

```DatabaseHelper.java
package com.example.myapplication;

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

import java.util.ArrayList;
import java.util.List;


public class DatabaseHelper extends SQLiteOpenHelper {

    private static final String DATABASE_NAME = "mydatabase.db"; // データベース名
    private static final int DATABASE_VERSION = 1; //データベース更新時にバージョンの値を上げていくこと
    private static final String TABLE_NAME_USERS = "users"; //生成するテーブル名
    private static final String USERS_COLUMN_ID = "id"; // テーブル内の属性1
    private static final String USERS_COLUMN_NAME = "name";// テーブル内の属性2
    private static final String USERS_COLUMN_EMAIL = "email";// テーブル内の属性3


    //コンストラクタを定義
    public DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    
    // データベースが初めて作成されたときに呼び出される
    @Override
    public void onCreate(SQLiteDatabase db) {
        String createTableQuery = "CREATE TABLE " + TABLE_NAME_USERS + " (" +
                USERS_COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
                USERS_COLUMN_NAME + " TEXT, " +
                USERS_COLUMN_EMAIL + " TEXT)";
        db.execSQL(createTableQuery);
    }


    //データベースのバージョンが変更されたときに呼び出されるテーブルをアップグレードするメソッド
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME_USERS);
        onCreate(db);
    }

    //データベースからすべてのユーザーを取得するメソッド
    public List<User> getAllUsers() {
        List<User> users = new ArrayList<>();
        SQLiteDatabase db = getReadableDatabase();
        Cursor cursor = db.query(TABLE_NAME_USERS, null, null, null, null, null, null);
        while (cursor.moveToNext()) {
            int id = cursor.getInt(cursor.getColumnIndexOrThrow(USERS_COLUMN_ID));
            String name = cursor.getString(cursor.getColumnIndexOrThrow(USERS_COLUMN_NAME));
            String email = cursor.getString(cursor.getColumnIndexOrThrow(USERS_COLUMN_EMAIL));
            users.add(new User(id, name, email));
        }
        cursor.close();
        db.close();
        return users;
    }

}

```

DATABASE_NAMEはデバイス内に保存されるSQLiteデータベースファイルのファイル名になるので覚えておくこと．

### 4.MainActivity.java
```MainActivity.java
package com.example.myapplication;

import android.os.Bundle;
import android.widget.ListView;

import androidx.appcompat.app.AppCompatActivity;

import java.util.List;

public class MainActivity extends AppCompatActivity {

    private DatabaseHelper databaseHelper;
    private UserAdapter userAdapter;

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

        databaseHelper = new DatabaseHelper(this);

        // データ取得
        List<User> users = databaseHelper.getAllUsers();

        // リストビューにデータ表示
        userAdapter = new UserAdapter(this, users);
        ListView userListView = findViewById(R.id.userListView);
        userListView.setAdapter(userAdapter);
    }

}
```
以上でデータベース構築は完了である．これでアプリを実行したら，デバイス内の`data/data/com.example.myapplication/databases/mydatabase.db`にテーブルが作成されているはずだ．このファイルをデータベースGUIソフトウェアで閲覧すればアクセスできる．
>com.example.myapplicationは最初に設定したPackage nameである．
>mydatabase.dbはDatabaseHelper.javaで作成したDATABASE_NAMEである．

## 4．データベースファイルをデバイスから取得
AndroidStudio上部の表示-ツールウィンドウ-DeviceExplorerを選択すると右側にデバイス内のファイル一覧が表示される．
![スクリーンショット 2024-04-19 14.07.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3757442/554240e3-b026-fb56-cf07-a1082af8743f.png)
表示されたら
`data/data/com.example.myapplication/databases/mydatabase.db`
を探して右クリック(macは左クリックまたはctl+右クリック)してSaveを選択し，PCのローカルに保存する．
>この時`mydatabase.db`の保存先のパスを覚えておくこと．


## 5．GUIソフトでテーブルにデータを追加，編集，削除
任意のデータベースGUIソフトウェアをインストールする．今回はTablePlusを使用する．
https://tableplus.com

ソフトウェアを開いたら上部に＋ボタンがあるので押したら以下の画面になるはずである．
![スクリーンショット 2024-04-19 12.26.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3757442/75c2a78d-ba70-3e41-e141-8a1443e5b7bb.png)
SQLiteを選択し，`Database Path`に先ほどPCのローカル上に保存した`mydatabase.db`のパスを入力し，Connectを選択する．
>`Name`はなんでもいい

![スクリーンショット 2024-04-19 14.26.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3757442/e4c5f8cf-9ac1-8863-3a4b-d393d1a03079.png)

するとusersテーブルが作成されていることがわかるので選択すると設定したid,name,email属性がテーブル内にあることがわかる．
>テーブル名はDatabaseHelper.javaで作成したTABLE_NAME_USERSである．

![スクリーンショット 2024-04-19 14.28.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3757442/97a6cadd-6e26-eb44-63ec-b686f5bd40c4.png)

テーブル内でダブルクリックをしてテーブルにデータを追加する．**追加した際にctrl+S(macはcmd+S)で保存する**
>保存は忘れないこと！！！

![スクリーンショット 2024-04-19 14.44.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3757442/92de88cf-817d-0b4b-46b6-b8b6703608b5.png)

>データを編集，削除する際はデータを右クリック(macは左クリックまたはctl+右クリック)して編集，削除することができる．**編集，削除時も保存は忘れないこと！！！**

## 6．データベースファイルをデバイスに適用
既存の`mydatabase.db`を削除してPC上の`mydatabase.db`をdatabasesディレクトリにドラッグ&ドロップして適用させる．
![スクリーンショット 2024-04-19 14.50.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3757442/c3495ae6-e9c7-d82a-e795-1fd84f139fd1.png)

この状態でアプリを実行すると以下のように画面にデータが表示されていれば完了である．
![Screenshot_2024-04-19-14-52-57-41_ee015900260ab508ba0bf0f18dc28a83.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3757442/4793653e-3bf5-1de3-47f7-aa3201be9206.jpeg)


## `補足`　テーブルを追加するには
table2(id,context)テーブルを作成するとする．Table2.java(モデルクラス)とTable2Adapter.java(アダプタークラス)をUserテーブル作成時の時と同様に作成しDatabaseHelper.javaに以下のコードを追記する．

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

    //データベース名
    private static final int DATABASE_VERSION = 2; //データベースを更新したのでバージョンを1から２にした

    //usersテーブル名と属性
    
    private static final String TABLE_NAME_TABLE2 = "table2"; //生成するテーブル名
    private static final String TABLE2_COLUMN_ID = "id"; // テーブル内の属性1
    private static final String TABLE2_COLUMN_CONTEXT = "context";// テーブル内の属性2

    //コンテキスト用メソッド　DatabaseHelper(Context context)

    @Override
    public void onCreate(SQLiteDatabase db) {
        //既存のテーブル用のcreate table

        //table2用のcreate tableを作成する．
        String createTableQuery = "CREATE TABLE " + TABLE_NAME_TABLE2 + " (" +
                TABLE2_COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
                TABLE2_COLUMN_CONTEXT + " TEXT)";
        db.execSQL(createTableQuery);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    //既存のテーブルのdrop tableとonCreate()の呼び出し
    
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME_TABLE2);
        onCreate(db);
    }

    //既存のusersテーブル用のデータ取り出しメソッド　getAllUsers()

    public List<Table2> getAllTable2() {
        List<Table2> table2 = new ArrayList<>();
        SQLiteDatabase db = getReadableDatabase();
        Cursor cursor = db.query(TABLE_NAME_Table2, null, null, null, null, null, null);
        while (cursor.moveToNext()) {
            int id = cursor.getInt(cursor.getColumnIndexOrThrow(Table2_COLUMN_ID));
            String context = cursor.getString(cursor.getColumnIndexOrThrow(Table2_COLUMN_CONTEXT));
            table2.add(new User(id, context));
        }
        cursor.close();
        db.close();
        return table2;
    }

}

```
これでアプリを実行したら`mydatabase.db`にtable2テーブルが追加される．