大量データの読み書き、さらに検索したい場合はデータベースが便利で、AndroidではSQLiteを使います。ここでは簡単な例を試してみます。
2021.2.1
SQLite
最初にGoogleはデータベースとして Room を推奨しています。
Room は、SQLite 全体を対象とする抽象化レイヤを提供して、
SQLite を最大限に活用しつつ、スムーズなデータベース アクセスを可能にしてくれるそうです。
SQLiteが使えないわけではないのですが、色々面倒な操作が簡単になったRoomを使ってくれとのことです。ここでは、それでもSQLiteが…という人のため残しておきます。
Roomの関連ページです
Room を使用してローカル データベースにデータを保存する
Room | Android デベロッパー | Android Developers
Room 永続ライブラリ | Android デベロッパー | Android …
~~~
SQLiteのデータは表のような構造で、関係(Relation)と呼ぶ概念でモデル化されています。例えば企業の株価をこのようにデータベース化されているとすると
番号 | 企業名 | 株価(USD) |
001 | Apple | 217 |
002 | 1105 | |
003 | Amazon | 1764 |
004 | Microsoft | 108 |
… |
このようなデータベースをSQLiteで作りAndroidで表示させてみましょう。
SQLiteOpenHelper
データベースの作成、データの追加・削除などを管理するためにSQLiteOpenHelperのクラスがあります。これを継承したクラスを作成するところから始めます。
例えばSQLiteOpenHelperを継承したTestOpenHelperというクラスを作ります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
public class TestOpenHelper extends SQLiteOpenHelper { // データーベースのバージョン private static final int DATABASE_VERSION = 1; // データーベース名 private static final String DATABASE_NAME = "TestDB.db"; 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); // context: コンテキスト // DATABASE_NAME: データベースファイル名 // factory: カーソルのファクトリー // DATABASE_VERSION: データベースのバージョン } @Override public void onCreate(SQLiteDatabase db) { // テーブル作成 db.execSQL( SQL_CREATE_ENTRIES ); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // アップデートの判別、古いバージョンは削除して新規作成 if(db != null){ db.execSQL( SQL_DELETE_ENTRIES ); onCreate(db); } } public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { onUpgrade(db, oldVersion, newVersion); } } |
onCreate() でテーブルを作成して、バージョンをあげると onUpgrade() にて新規バージョンのテーブルが作成されバージョンアップします。
TestDB.dbは
/data/data/[your.package.name]/database/
以下に作成されています
データベースの作成・削除
テーブル作成やアップデートの判別の execSQL() にはSQL文で実行文を文字列で入れて指定します。例えばSQL_CREATE_ENTRIESはこのように記述します。
1 2 |
"CREATE TABLE testdb ( _id INTEGER PRIMARY KEY, items TEXT, "+ "price INTEGER)" |
これを汎用性と意味がわかるようにしてまとめるとこうなります。(注)文なのでスペースは意味がありますので消さないように
1 2 3 4 5 |
private static final String SQL_CREATE_ENTRIES = "CREATE TABLE " + TABLE_NAME + " (" + _ID + " INTEGER PRIMARY KEY," + COLUMN_NAME_TITLE + " TEXT," + COLUMN_NAME_SUBTITLE + " INTEGER)"; |
同様にSQL_DELETE_ENTRIESもこのように書き換えられます。
1 2 |
private static final String SQL_DELETE_ENTRIES = "DROP TABLE IF EXISTS " + TABLE_NAME; |
データ追加
データの書き込みは execSQL() を使うこともできますが、ContentValueを使いマップデータ型のkeyとvalueとして扱うことも可能です。
1 2 3 4 5 6 7 |
public void saveData(SQLiteDatabase db, String item, int price){ ContentValues values = new ContentValues(); values.put("items", item); values.put("price", price); db.insert("testdb", null, values); } |
データ読み出し
読み出しは query() メソッドを使います。実際にここではテーブル名とコラム名の配列を設定するだけの簡単なものとして作りました。
1 2 3 4 5 6 7 8 9 |
Cursor cursor = db.query( TABLE_NAME, // The table to query projection, // The array of columns to return (pass null to get all) selection, // The columns for the WHERE clause selectionArgs,// The values for the WHERE clause null, // don't group the rows null, // don't filter by row groups sortOrder // The sort order ); |
サンプルコード
まとめてみます。EditTextからデータを入力してデータベースを作ってみます。
TestOpenHelper.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
//package your.package.name; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; public class TestOpenHelper extends SQLiteOpenHelper { // データーベースのバージョン private static final int DATABASE_VERSION = 1; // データーベース名 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 = "company"; private static final String COLUMN_NAME_SUBTITLE = "stockprice"; 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) { // テーブル作成 // SQLiteファイルがなければSQLiteファイルが作成される db.execSQL( SQL_CREATE_ENTRIES ); Log.d("debug", "onCreate(SQLiteDatabase db)"); } @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); } } |
ActivityからContextをSQLiteOpenHelperを継承したTestOpenHelperに渡し、データベースを作成。読み出しをボタンでデータベースから読出し表示させます。
MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
//package your.package.name; import androidx.appcompat.app.AppCompatActivity; import android.content.ContentValues; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import android.util.Log; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class MainActivity extends AppCompatActivity { private TextView textView; private EditText editTextKey, editTextValue; private TestOpenHelper helper; private SQLiteDatabase db; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); editTextKey = findViewById(R.id.edit_text_key); editTextValue = findViewById(R.id.edit_text_value); textView = findViewById(R.id.text_view); Button insertButton = findViewById(R.id.button_insert); insertButton.setOnClickListener(v -> { if(helper == null){ helper = new TestOpenHelper(getApplicationContext()); } if(db == null){ db = helper.getWritableDatabase(); } String key = editTextKey.getText().toString(); String value = editTextValue.getText().toString(); // 価格は整数を想定 insertData(db, key, Integer.parseInt(value)); }); Button readButton = findViewById(R.id.button_read); readButton.setOnClickListener(v -> readData()); } private void readData(){ if(helper == null){ helper = new TestOpenHelper(getApplicationContext()); } if(db == null){ db = helper.getReadableDatabase(); } Log.d("debug","**********Cursor"); Cursor cursor = db.query( "testdb", new String[] { "company", "stockprice" }, 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"); cursor.moveToNext(); } // 忘れずに! cursor.close(); Log.d("debug","**********"+sbuilder); textView.setText(sbuilder.toString()); } private void insertData(SQLiteDatabase db, String com, int price){ ContentValues values = new ContentValues(); values.put("company", com); values.put("stockprice", price); db.insert("testdb", null, values); } } |
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
<?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" android:background="#dfe" tools:context=".MainActivity"> <EditText android:id="@+id/edit_text_key" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="50dp" android:autofillHints="@string/hint_key" android:background="#fff" android:hint="@string/hint_key" android:inputType="text" android:textSize="30sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintRight_toLeftOf="@+id/edit_text_value" app:layout_constraintVertical_bias="0.05" /> <EditText android:id="@+id/edit_text_value" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="50dp" android:autofillHints="@string/hint_value" android:background="#fff" android:hint="@string/hint_value" android:inputType="numberDecimal" android:textSize="30sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toRightOf="@+id/edit_text_key" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.05" /> <Button android:id="@+id/button_insert" android:layout_width="0dp" android:layout_height="wrap_content" android:text="@string/insert" android:textSize="20sp" android:layout_marginStart="20dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintVertical_bias="0.1" app:layout_constraintRight_toLeftOf="@+id/button_read" app:layout_constraintTop_toBottomOf="@+id/edit_text_key" /> <Button android:id="@+id/button_read" android:layout_width="0dp" android:layout_height="wrap_content" android:text="@string/read" android:textSize="20sp" android:layout_marginEnd="20dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintVertical_bias="0.1" app:layout_constraintLeft_toRightOf="@+id/button_insert" app:layout_constraintTop_toBottomOf="@+id/edit_text_value" /> <TextView android:id="@+id/text_view" android:layout_width="250dp" android:layout_height="wrap_content" android:textSize="32sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/button_read" app:layout_constraintVertical_bias="0.2" /> </androidx.constraintlayout.widget.ConstraintLayout> |
リソース
strings.xml
1 2 3 4 5 6 7 |
<resources> <string name="app_name">Your App Name</string> <string name="hint_key">company</string> <string name="hint_value">US$price</string> <string name="insert">insert</string> <string name="read">read</string> </resources> |
データとして企業名と株価をEditTextに入れてデータベースを作っていきます。尚、価格は整数で扱うようにしていますので小数点を使う場合はコードを変更してください。
次は、実際にデータが保存されているのを確認します。
関連ページ:
References:
Save data using SQLite | Android Developers
SQLite Home Page