📌

【Kotlin】Android で各ストレージの総容量、空き容量を取得する方法

2021/03/13に公開

Android 10(Q)から導入された Scoped Storage の影響で、以前のストレージの容量関連の取得ができなくなっていたため、Android 10 以降でも利用できる方法を模索したのでメモしておきます。
※ ディレクトリ毎のパーミッションを取ればできますが、
 容量関連の情報を取るためだけに、ユーザにパーミッション許可を求めたくなかったため、
  StatFs を用いた方法にしてあります。

なお、勢いで書いたので、実際には動かしてないです。。。
※サンプルコードの他に外部ストレージアクセスのパーミッション取得が必要な可能性あり。

サンプルコード

MainActivity.kt
package com.example.storage.ui

import android.annotation.SuppressLint
import android.os.Build
import android.os.Bundle
import android.os.StatFs
import android.os.storage.StorageManager
import android.os.storage.StorageVolume
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import java.util.*

/**
 * Main Activity
 */
class MainActivity : AppCompatActivity() {
  /**
   * ==============================================
   *  インスタンス変数
   * ==============================================
   */
  /** タグ */
  private val tag: String = "MainActivity"

  /** ストレージマネージャー */
  private val storageManager: StorageManager?
    get() = getSystemService(StorageManager::class.java)

  /**
   * ==============================================
   *  ライフサイクルイベント
   * ==============================================
   */
  /**
   * onCreate
   */
  @SuppressLint("DiscouragedPrivateApi")
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    Log.i(tag, "onCreate")

    for (storageVolume: StorageVolume in storageManager!!.storageVolumes) {
      // ストレージボリュームのリストを取得し、1件づつ処理
      // ストレージボリュームから絶対パスを取得
      val path: String = when {
        Build.VERSION.SDK_INT>= Build.VERSION_CODES.R -> {
          // Android 11以降
          storageVolume.directory?.absolutePath
        }
        else -> {
          // Android 10以前
          // NOTE: Android10以前ではgetPathがprivateなため無理やり実行して取得
          val getPath = StorageVolume::class.java.getDeclaredMethod("getPath")
          getPath.invoke(storageVolume) as String?
        }
      } ?: continue // 絶対パスが取得できない場合は、スキップ

      val statFs = StatFs(path)
      // 総容量
      val totalSpase: Long = statFs.blockCountLong * statFs.blockSizeLong / 1024L / 1024L
      // 空き容量
      val freeSpase: Long = statFs.availableBlocksLong * statFs.blockSizeLong / 1024L / 1024L
      // 使用容量
      val usedSpase: Long = totalSpase - freeSpase

      Log.d(tag, "Path: $path")
      Log.d(tag, " Used space: ${String.format(Locale.US, "%,12d", usedSpase)}MB")
      Log.d(tag, " Free space: ${String.format(Locale.US, "%,12d", freeSpase)}MB")
      Log.d(tag, "Total space: ${String.format(Locale.US, "%,12d", totalSpase)}MB")
      Log.d(tag, "Total space: ${String.format(Locale.US, "%,12d", totalSpase)}MB")
    }
  }
}

実行結果

Log
 Path: /storage/emulated/0
  Used space:          495MB
  Free space:        5,455MB
 Total space:        5,951MB
 Path: /storage/1200-3709
  Used space:            0MB
  Free space:          509MB
 Total space:          509MB
GitHubで編集を提案
株式会社ナンバーフォー

Discussion