Storage
Shared Preferences
アプリケーション固有の設定を記録しておくには、Key-Value ストアの SharedPreferences を用いるとよい。保存可能な値はプリミティブ型 boolean / int / long float / String に限る。
private static final String PREF_NAME = "settings";
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
SharedPreferences settings = getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
String foo = settings.getString("foo");
}
...
protected void onStop() {
SharedPreferences settings = getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = settings.edit();
settings.putString("foo", "bar");
...
super.onStop();
}
SharedPreferences の読み書きには、それなりのコストがかかるため、ユーザ操作ごとに更新してはならない。更新タイミングは、HONEYCOMB 以降のみのサポートなら Activity#onStop
でよい。それ以前のバージョンでは、onStop
が呼ばれない場合があるため onPause
で保存する。
Internal Storage
Internal Storage には、アプリケーション固有のファイルを保存する。アプリケーションを介する読み書きのみで、ユーザ自身がファイルを操作することはできない。アプリケーションのアンインストールにより削除される。
により、得られるファイルストリームに対し読み書きすれば良い。
キャッシュなどの一時ファイルは Context#getCacheDir により得られるディレクトリ以下に保存する。このディレクトリ内のファイルは、容量が足りなくなった時などの必要時に応じて削除される。
External Storage
External Storage には、ユーザ自身が操作可能なファイル(写真 / 動画 / ダウンロードファイル 等)を保存する。
取り外し可能な、SDカードなどのリムーバブルストレージのみを指すわけではない。端末内部にも仮想デバイスとして External Storage が提供される。
Environment.getExternalStorageDirectory により External Storage のディレクトリが得られる。(READ|WRITE)_EXTERNAL_STORAGE
のパーミッションを持っていれば、このディレクトリ以下の全てのファイルにアクセスできる。
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Internal Storage とは異なり、アプリケーション外から全てのファイル操作が可能である。
- 外部アプリケーションから、ファイル読み書きが可能
- USBデバイスとして、ユーザ自身がファイルを操作することが可能
このため、漏洩 / 改変されると問題のあるデータ(ポイント/認証トークン/パスワード等)を保存してはならない。セキュリティ的には問題がないデータであっても、改変されてはならないアプリケーション固有のデータは Internal Storage を使う。
Public Directory
Environment.getExternalStoragePublicDirectory により、ファイル種別毎の共有ディレクトリを取得できる。
File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
システムが、ファイル種別毎に区分けしたディレクトリであって、保存するファイル種別の制限はない。アプリケーション自身でハンドリングを行なう必要がある。
Application Directory
Context#getExternalFilesDir により、アプリケーション用の保存ディレクトリを取得できる。
このディレクトリはアプリケーションのアンインストールとともに削除される。写真などの共有データや購入コンテンツを保存してはならない。Internal Strage に収まりきらない、漏洩や改変があっても問題ないファイルを保存し、アンインストールとともに削除されるべきファイルを保存する。
他アプリケーションとのファイル名衝突がないように、システムによりアプリケーション用に区分けされたディレクトリであって、External Storage へのパーミッションを持つアプリケーションはアクセス可能である点に注意する。
Android 4.4 (API19) 以降では、自身のパッケージのディレクトリであれば、パーミッションを持たなくてもアクセスできる。Public Directory へのアクセスが不要なら maxSdkVersion
を指定しておくとよい。
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18" />
API19 以降の端末のみで動作確認すると、パーミッションの追加を忘れてしまいがちなので注意する。
Error Handling
External Storage がリムーバブルである場合、マウントされていなければ利用可能できない。
- Context#getExternalFilesDir は、アクセスできない場合には
null
が返る。 - Environment#getExternalStorageState でマウント状態を取得できる。
- Environment.html#getExternalStorageDirectory
ACTION_MEDIA_(MOUNTED|REMOVED)
の Broadcast が送信されるので、レシーバを登録しておくこともできる。
Multi User
Android 4.2 よりマルチユーザに対応している。Internal Storage および、端末内部の External Storage には、ユーザID毎のディレクトリが作成され、利用ユーザごとのアプリケーションデータが作成されることになる。
- Internal Storage:
/data/user/(ユーザID)
- External Storage:
/storage/emulated/(ユーザID)
External Storage がリムーバブルの場合には、マルチユーザとはならない。
アプリケーション側では、シングル/マルチユーザの違いは意識せず API を介してディレクトリを取得すればよい。ディレクトリ名は端末により異なるので、直接ファイルパスを指定してはならない。
エミュレータではシングルユーザに制限されている。Android 4.2(API17) 系のエミュレータであれば、adb shell
を介して fw.max_users
で最大ユーザ数を指定することで、マルチユーザを利用することができる。
$ adb shell
root@generic:/ # pm get-max-users
Maximum supported users: 1
root@generic:/ # setprop fw.max_users 8
root@generic:/ # pm get-max-users
Maximum supported users: 8