モーダルを閉じる工作HardwareHub ロゴ画像

工作HardwareHubは、ロボット工作や電子工作に関する情報やモノが行き交うコミュニティサイトです。さらに詳しく

利用規約プライバシーポリシー に同意したうえでログインしてください。

目次目次を開く/閉じる

Android におけるデータ保存

モーダルを閉じる

ステッカーを選択してください

お支払い手続きへ
モーダルを閉じる

お支払い内容をご確認ください

購入商品
」ステッカーの表示権
メッセージ
料金
(税込)
決済方法
GooglePayマーク
決済プラットフォーム
確認事項

利用規約をご確認のうえお支払いください

※カード情報はGoogleアカウント内に保存されます。本サイトやStripeには保存されません

※記事の執筆者は購入者のユーザー名を知ることができます

※購入後のキャンセルはできません

作成日作成日
2017/08/12
最終更新最終更新
2019/11/17
記事区分記事区分
一般公開

Android におけるデータ保存の方法は主に三つ用意されています。それぞれの利用方法をまとめます。

関連する公式ドキュメント

環境設定値として保存 (Shared Preferences)

環境設定を簡易 KVS として利用できます。ファイルに保存されるため、アプリケーションが kill されても値は消失しません。

以下のサンプルでは Shared Preferences を直接利用していますが、そうではなくこれを内部的に利用して、アプリケーション設定の UI を構築するための仕組みが存在します。簡易 KVS ではなくアプリケーションの設定をユーザーが管理する UI を作成するためには後者を利用すると簡単です。

package com.example.mycompany.myapp;

import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";
    private static final String PREF_FILE_NAME = "com.example.mycompany.myapp.PREF_FILE_NAME";

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

        // 設定ファイルを開きます。
        SharedPreferences sharedPref = getSharedPreferences(PREF_FILE_NAME, Context.MODE_PRIVATE);

        // 値の取得
        int intVal = sharedPref.getInt("MY_KEY", 123); // 既定値 123 を設定
        Log.d(TAG, "MY_VALUE: " + intVal);

        // 値の設定 (起動する毎に値が +1 されます)
        SharedPreferences.Editor editor = sharedPref.edit();
        editor.putInt("MY_KEY", intVal + 1);
        editor.commit();
    }
}

実行例

08-12 11:49:41.905 5893-5893/com.example.mycompany.myapp D/MainActivity: MY_VALUE: 123
↓終了して再度起動
08-12 11:50:13.073 5893-5893/com.example.mycompany.myapp D/MainActivity: MY_VALUE: 124
↓終了して再度起動
08-12 11:50:28.786 5893-5893/com.example.mycompany.myapp D/MainActivity: MY_VALUE: 125

ファイル保存

Android ファイルシステムには、常に利用可能であることが保証されておりアプリケーション外からアクセスすることを基本的に想定しない Internal なものと、SD カード等によって提供される常に利用できるとは限らず、他のアプリケーションやユーザーからも参照される可能性のある External なものがあります。以下のサンプルは Internal なファイルシステムに対して読み書きしています。External なファイルシステムに対して操作を行う際は、利用可能かどうかの事前判定や AndroidManifest.xml におけるユーザーへの Permission 許可依頼が別途必要です。

package com.example.mycompany.myapp;

import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

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

        // 書き込み
        BufferedWriter writer = null;
        try {
            writer = new BufferedWriter(new OutputStreamWriter(openFileOutput("my_file.txt", Context.MODE_PRIVATE)));
            writer.write("abc\n123");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(writer != null) {
                    writer.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        // 読み出し
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new InputStreamReader(openFileInput("my_file.txt")));
            String str = null;
            while((str = reader.readLine()) != null) {
                Log.d(TAG, str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(reader != null) {
                    reader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        // Internal ファイルシステムにおける保存場所
        Log.d(TAG, "saved dir: " + getFilesDir());

        // 保存されているファイルリスト
        String[] files = fileList();
        for(int i = 0; i < files.length; ++i) {
            Log.d(TAG, "found: " + files[i]);
            deleteFile(files[i]); // 削除
        }
    }
}

Java 7 相当以上の API レベルであれば try-with-resources 構文を利用した記述が可能です。また、Android Studio におけるファイルエクスプローラは「Tools → Android → Android Device Monitor → File Explorer」で利用できます。

実行例

08-12 19:17:03.878 5837-5837/com.example.mycompany.myapp D/MainActivity: abc
08-12 19:17:03.878 5837-5837/com.example.mycompany.myapp D/MainActivity: 123
08-12 19:17:03.879 5837-5837/com.example.mycompany.myapp D/MainActivity: saved dir: /data/user/0/com.example.mycompany.myapp/files
08-12 19:17:03.879 5837-5837/com.example.mycompany.myapp D/MainActivity: found: my_file.txt

SQLite DB 保存

Android では Rails でも既定の設定で利用されている SQLite が組み込み DB として利用できます。上述「ファイル保存」における Internal ファイルシステムと同様、保存された情報は他のアプリケーションから参照できません。以下のサンプルでは簡単のため main スレッドで DB 操作していますが、一般に時間のかかる処理であり実際のアプリケーション開発時には IntentService などで別スレッドを用意するようにします。

MyDbContract.java

contract class とよばれるクラスを用意し、そのインナークラスで各テーブルを定義します。

package com.example.mycompany.myapp;

import android.provider.BaseColumns;

public final class MyDbContract {
    // コンストラクタを利用できないようにします。
    private MyDbContract() {}

    // テーブル名、列名の定数定義です。
    public static class MyTable implements BaseColumns {
        public static final String TABLE_NAME = "my_table";
        public static final String COLUMN_NAME_INT_COL = "int_col";
        public static final String COLUMN_NAME_STR_COL = "str_col";
    }
}

MyDbHelper.java

後に MainActivity で DB 操作のために利用するクラスです。先程定義した contract class 内の MyTable を static インポートしています。

package com.example.mycompany.myapp;

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

import static com.example.mycompany.myapp.MyDbContract.MyTable;

public class MyDbHelper extends SQLiteOpenHelper {

    // スキーマに変更があれば VERSION をインクリメントします。
    public static final int DATABASE_VERSION = 1;

    // SQLite ファイル名を指定します。
    public static final String DATABASE_NAME = "MyDb.db";

    // SQLite ファイルが存在しない場合や VERSION が変更された際に実行する SQL を定義します。
    private static final String SQL_CREATE_TABLE =
            "CREATE TABLE " + MyTable.TABLE_NAME + " (" +
                    MyTable._ID + " INTEGER PRIMARY KEY," +
                    MyTable.COLUMN_NAME_INT_COL + " INTEGER," +
                    MyTable.COLUMN_NAME_STR_COL + " TEXT)";

    private static final String SQL_DROP_TABLE = "DROP TABLE IF EXISTS " + MyTable.TABLE_NAME;

    public MyDbHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) { // SQLite ファイルが存在しない場合
        db.execSQL(SQL_CREATE_TABLE);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // VERSION が上がった場合に実行されます。本サンプルでは単純に DROP して CREATE し直します。
        db.execSQL(SQL_DROP_TABLE);
        onCreate(db);
    }

    @Override
    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // VERSION が下がった場合に実行されます。本サンプルでは単純に DROP して CREATE し直します。
        onUpgrade(db, oldVersion, newVersion);
    }
}

MainActivity.java

簡単のためすべて onCreate() 内でクエリを実行しています。実際にはバックグラウンドで別スレッドで処理すべきです。また、コネクションを張る処理は重いため onDestroy() で閉じるまで使い回しています。

package com.example.mycompany.myapp;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

import static com.example.mycompany.myapp.MyDbContract.MyTable;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    // DB を操作するためのインスタンス
    private MyDbHelper mDbHelper = null;

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

        mDbHelper = new MyDbHelper(getApplicationContext());
        SQLiteDatabase reader = mDbHelper.getReadableDatabase();
        SQLiteDatabase writer = mDbHelper.getWritableDatabase();

        // INSERT
        ContentValues values = new ContentValues();
        values.put(MyTable.COLUMN_NAME_INT_COL, 123);
        values.put(MyTable.COLUMN_NAME_STR_COL, "aaa");
        writer.insert(MyTable.TABLE_NAME, null, values);

        // SELECT
        String[] projection = { // SELECT する列
                MyTable._ID,
                MyTable.COLUMN_NAME_INT_COL,
                MyTable.COLUMN_NAME_STR_COL
        };
        String selection = MyTable.COLUMN_NAME_INT_COL + " = ?"; // WHERE 句
        String[] selectionArgs = { "123" };
        String sortOrder = MyTable.COLUMN_NAME_STR_COL + " DESC"; // ORDER 句
        Cursor cursor = reader.query(
                MyTable.TABLE_NAME, // The table to query
                projection,         // The columns to return
                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
        );
        while(cursor.moveToNext()) {
            long id = cursor.getLong(cursor.getColumnIndexOrThrow(MyTable._ID));
            String str = cursor.getString(cursor.getColumnIndexOrThrow(MyTable.COLUMN_NAME_STR_COL));
            Log.d(TAG, "id: " + String.valueOf(id) + ", str: " + str);
        }
        cursor.close();

        // DELETE
        String deleteSelection = MyTable._ID + " > ?"; // WHERE 句
        String[] deleteSelectionArgs = { "5" };
        writer.delete(MyTable.TABLE_NAME, deleteSelection, deleteSelectionArgs);

        // UPDATE
        ContentValues updateValues = new ContentValues();
        updateValues.put(MyTable.COLUMN_NAME_STR_COL, "bbb");
        String updateSelection = MyTable.COLUMN_NAME_STR_COL + " = ?";
        String[] updateSelectionArgs = { "aaa" };
        writer.update(
            MyTable.TABLE_NAME,
            updateValues,
            updateSelection,
            updateSelectionArgs);
    }

    @Override
    protected void onDestroy() {
        if(mDbHelper != null) {
            mDbHelper.close(); // コネクションを閉じます。
        }
        super.onDestroy();
    }
}

adb コマンドで SQLite に接続してデバッグ

Android Studio で SDK と同封されてインストールされる adb (Android Debug Bridge) コマンドを利用すると Android 端末に shell で接続できます。「Preferences → Appearance & Behavior → System Settings → Android SDK → Android SDK Location」で SDK の場所を確認して PATH を通しておきます。

$ /Users/username/Library/Android/sdk/platform-tools/adb shell
generic_x86:/ $ su
generic_x86:/ #

SQLite DB ファイルの場所を探します。

generic_x86:/ # find . -name 'MyDb.db'
...
./data/data/com.example.mycompany.myapp/databases/MyDb.db

sqlite3 コマンドで接続します。

generic_x86:/ # sqlite3 ./data/data/com.example.mycompany.myapp/databases/MyDb.db

テーブル一覧

sqlite> .tables
android_metadata  my_table

スキーマ確認

sqlite> .schema my_table
CREATE TABLE my_table (_id INTEGER PRIMARY KEY,int_col INTEGER,str_col TEXT);

SQL 発行

sqlite> select * from my_table;
1|123|bbb
2|123|bbb
3|123|bbb
4|123|bbb
5|123|bbb
Likeボタン(off)0
詳細設定を開く/閉じる
アカウント プロフィール画像

Android Developer

記事の執筆者にステッカーを贈る

有益な情報に対するお礼として、またはコメント欄における質問への返答に対するお礼として、 記事の読者は、執筆者に有料のステッカーを贈ることができます。

>>さらに詳しくステッカーを贈る
ステッカーを贈る コンセプト画像

Feedbacks

Feedbacks コンセプト画像

    ログインするとコメントを投稿できます。

    ログインする

    関連記事

    • Spring Security フォームログインのサンプルコード
      Spring フレームワークによる Web アプリケーション開発で、ログイン処理を実装する際は Spring Security が便利です。ここでは特に Spring Boot で Web アプリケーションを開発する場合を対象とし、フォームによる ID/Password ログインを行うためのサンプルコードをまとめます。 公式ドキュメント [Spring Security チュートリアル](http...
      えびちゃんえびちゃん11/4/2019に更新
      いいねアイコン画像0
    • Java配列の宣言方法 (C/C++との違い)
      Javaの配列 Javaの配列宣言方法はC/C++と似ているようで若干異なる。 初期化しない場合 C/C++の int array[10]; はJavaでは int array[] = new int[10]; となる。同様にC/C++の int array[3][3]; はJavaでは int array[][] = new int[3][3]; となる。 初期化
      てんとうむしてんとうむし4/13/2018に更新
      いいねアイコン画像0
    • PlantUML による UML 図の描き方
      サムネイル画像-c788fffde5
      PlantUML はテキスト形式で表現されたシーケンス図やクラス図といった UML (Unified Modeling Language) 図の情報から画像を生成するためのツールです。簡単な使い方をまとめます。 インストール方法の選択 Atom や Eclipse のプラグインをインストールしてエディタから利用する方法、JAR をダウンロードして Java コマンドで実行する方法、Redmine ...
      kentakenta12/21/2019に更新
      いいねアイコン画像0
    • Akka HTTP サンプルコード (Scala)
      サムネイル画像-a98142497c
      Akka アクターを用いて実装された汎用 HTTP フレームワークです。Spray の後継です。コアモジュールである akka-http-core は 2016/2/17 に experimental が外れました。akka-http などのいくつかのサブモジュールは 2016/3/1 現在 experimental のままですが、基本的な
      雄太雄太9/7/2021に更新
      いいねアイコン画像0
    • Kestrel の使用例
      Kestrel は Message Queue (MQ) の実装のひとつです。一般に MQ はアプリケーション間やプロセス間、スレッド間で非同期に通信するために用いられます。メッセージの送信側は MQ に書き込めば受信側の応答を待たずに次の処理に非同期に進むことができます。Kestrel はわずか 2500 行程の Scala で実装されており JVM で動作します。MQ 自体はメモリ上に存在する...
      したくんしたくん9/12/2017に更新
      いいねアイコン画像0