Picturesディレクトリは存在するとは限らない

getExternalStoragePublicDirectory()のディレクトリは存在するとは限らない

Picturesディレクトリは存在するとは限らない

Androidでディレクトリを指定して写真などを保存する際、API Level 29 (Android Q / 10) 以降はMediaStore APIを使いますが、まだまだAndroid 9以前への対応も必要ですので、従来通りEnvironment#getExternalStoragePublicDirectory()を使うことも多いと思います。画像であれば引数にDIRECTORY_PICTURESDIRECTORY_DCIMを指定し、以下のようにサブディレクトリを指定するのがよくあるパターンでしょう。

val path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
val folder = File(path, "subDirectoryName")
if (!folder.exists()) {
    /* subDirectoryが存在しない場合は作成する */
    val result = folder.mkdir()
}

しかし上記のコードには落とし穴があります。サブディレクトリが存在しない場合は想定されていますが、そもそもDIRECTORY_PICTURESが存在しない場合が想定されていません。結果、この先のファイル保存の処理が失敗することになります。

DIRECTORY_PICTURESで取得されるのは、一般的にはストレージのルート直下の”Pictures”ディレクトリですが、デバイスによってはこのディレクトリが存在しない場合があるのです。私が遭遇したのは、ASUSのスマートフォンでした。

mkdirs()を使う

ディレクトリが存在しないのであれば、作ってあげなければいけません。上記のコードではサブディレクトリを作成するためにmkdir()を使っていますが、この関数は親ディレクトリが存在しない場合は失敗します。親ディレクトリも含めて作成するには、mkdirs()を使えばよいです。

val path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
val folder = File(path, "subDirectoryName")
if (!folder.exists()) {
    /* subDirectoryが存在しない場合は作成する。*/
    /* 親ディレクトリが存在しない場合は親ディレクトリも作成する。 */
    val result = folder.mkdirs()
}

sが有るか無いかで、大違いですね。ちなみに公式リファレンスには、ちゃんと書いてあります。

Note that this directory may not yet exist, so you must make sure it exists before using it such as with File.mkdirs().

https://developer.android.com/reference/kotlin/android/os/Environment#getexternalstoragepublicdirectory

結局は、「ドキュメント読め」ですね。