アプリで使うちょっとしたデータを保存したい場合に SharedPreferences を使うと簡単にできます。但し、データが多くなるような場合は データベースを使うことが推奨されています。単純な初期化のための環境変数などの用途ということでしょう。
2024.1.1
SharedPreferences
このSharedPreferencesは「共有の環境設定」という日本語訳がされています。
- 共有の環境設定
- キーと値のペアでプリミティブ データを保存します。
- 内部ストレージ
- 端末のメモリにプライベート データを保存します。
- 外部ストレージ
- 共有外部ストレージにパブリック データを保存します。
- SQLite データベース
- プライベート データベースに構造化データを保存します。
- ネットワーク接続
- 独自のネットワーク サーバーを使用してウェブにデータを保存します。
Ref: ストレージ オプション | Android Developers
後で出てきますが、SharedPreferencesの実体はxmlファイルです。アプリ内のメモリにxmlファイルでの書き込み、読出しをする訳なので、大量のデータのやり取り、プロセスをまたがったデータ取得は問題が起きる可能性があるようです。
簡単な初期起動が済んだかどうか、true/false 程度のデータを保存するためには手軽です。
DataStoreというのがあります。SharedPreferencesの問題を解消できるようですが、まだアルファ、ベータの段階です。そのうちこちらが主流になるかもしれません。
SharedPreferences, Editor, MODE の設定
書込ケースでは
- SharedPreferences のインスタンス生成
- edit() を呼び出して SharedPreferences.Editor を取得
- putString() などのメソッドを使用して値を追加
- apply()あるいはcommit() を使用して新しい値を書き込む
String 書込む場合のコード
1 2 3 4 5 6 7 |
// ファイル名:DataStore SharedPreferences dataStore = getSharedPreferences("DataStore", MODE_PRIVATE); Editor editor = dataStore.edit(); // Key: input, value: text editor.putString("input", "abcdefg"); //editor.commit(); editor.apply(); |
書き込み方法にはapply()とcommit()があります。applyは非同期でcommit()は同期した処理ですから直ぐに書き込む必要性がない場合はapply()がいいようです。
apply()によると、非同期でよければこちらを使った方がいいが、問題がある場合はcommit()を使うというケースバイケースのようです。複数の書き込みが別スレッドで起きるような場合は注意しないといけません。
この例は、DataStore という名前で定義して、MODE_PRIVATE のモードで Key が input, value が例えば「abcdefg」を保存するケースです。モードは他にMODE_APPENDがあります。
- MODE_PRIVATE
- このアプリからのみ読み書き可
- MODE_APPEND
- 追加で書き込み
MODE_MULTI_PROCESSServiceで書きこんだデータをActivityで読み出す場合はこれが有効残念ながらAndroid6.0で非推奨になりました
String, Int, Boolean, Long, Float の保存と読み出しの例です。
1 2 3 4 5 6 7 8 9 10 11 12 |
// 保存 SharedPreferences data = getSharedPreferences("Data", MODE_PRIVATE); SharedPreferences.Editor editor = data.edit(); editor.putString("DataString", "sample"); editor.putInt("DataInt", 123); editor.putBoolean("DataBoolean", true); editor.putLong("DataLong", 12345678909876L); editor.putFloat("DataFloat", 12.345f); //editor.commit(); editor.apply(); |
1 2 3 4 5 6 |
// 読み出し String dataString = data.getString("DataString", null); int dataInt = data.getInt("DataInt", 0); boolean dataBoolean = data.getBoolean("DataBoolean", false); long dataLong = data.getLong("DataLong", 0); float dataFloat = data.getFloat("DataFloat", 0); |
サンプルコード
書き込みと読み出しができているか確認してみましょう。
Projectに入れてまとめると
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 |
package com.example.testsharedpreferences; import android.content.SharedPreferences; import android.os.Bundle; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import androidx.activity.EdgeToEdge; import androidx.appcompat.app.AppCompatActivity; import androidx.core.graphics.Insets; import androidx.core.view.ViewCompat; import androidx.core.view.WindowInsetsCompat; public class MainActivity extends AppCompatActivity { private SharedPreferences dataStore; private EditText editText; private TextView textWrite, textRead; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); EdgeToEdge.enable(this); setContentView(R.layout.activity_main); ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> { Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom); return insets; }); // "DataStore"という名前でインスタンスを生成 dataStore = getSharedPreferences("DataStore", MODE_PRIVATE); editText = findViewById(R.id.edit_text); textWrite = findViewById(R.id.text_write); textRead = findViewById(R.id.text_read); Button buttonWrite = findViewById(R.id.button_write); buttonWrite.setOnClickListener( v -> { // エディットテキストのテキストを取得 String text = editText.getText().toString(); textWrite.setText(text); // 入力文字列を"input"に書き込む SharedPreferences.Editor editor = dataStore.edit(); editor.putString("input", text); //editor.commit(); editor.apply(); }); Button buttonRead = findViewById(R.id.button_read); buttonRead.setOnClickListener( v -> { // "input"から読み出す、何もないときは"Nothing"を返す String str = dataStore.getString("input", "Nothing"); if(!str.equals("Nothing")) { textRead.setText(str); } }); } } |
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 |
<?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:id="@+id/main" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <EditText android:id="@+id/edit_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:autofillHints="@string/hint" android:hint="@string/hint" android:inputType="text" android:textSize="30sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.1" /> <Button android:id="@+id/button_write" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="40dp" android:layout_marginEnd="40dp" android:text="@string/write" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.3" /> <TextView android:id="@+id/text_write" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:textSize="50sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.4" /> <Button android:id="@+id/button_read" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="40dp" android:layout_marginEnd="40dp" android:text="@string/read" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.6" /> <TextView android:id="@+id/text_read" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:textColor="#0000ff" android:textSize="50sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.7" /> </androidx.constraintlayout.widget.ConstraintLayout> |
リソースです
strings.xml
1 2 3 4 5 6 |
<resources> <string name="app_name">TestSharedPreferences</string> <string name="hint">"文字を入力"</string> <string name="read">Read</string> <string name="write">Write</string> </resources> |
Device Explorer で確認
注)あくまでデバッグ段階でのファイル確認です
Android Studio で保存したデータを確認します
(注)昔はADMともDevice File Explorerともいっていました、その前はDDMSとも呼ばれているものです。
Device Explorerから /data/data/ 以下にパッケージ名があるのでそれを選択
その下の、Shared_pref フォルダーに設定した名前のxmlがあります。(DataStore.xml)
クリックするとxmlファイルだと言う事がわかります。
テストで設定した「test」が”input”のvalueとなっています。
1 2 3 4 |
<?xml version='1.0' encoding='utf-8' standalone='yes' ?> <map> <string name="input">test</string> </map> |
こんな風になっているのでした。
他にもコマンドの run-as を使って調べることもできます。
関連記事:
Kotlin:
References:
ストレージ オプション | Android Developers
SharedPreferences | Android Developers
apply()
Key-Value データを保存する
保存した値を使用する