對 Android app,可儲存 app 自身專屬(用) 檔案於 內部儲存空間 和 外部儲存空間,內部儲存空間很小,只適合存放小容量的檔案,若不是有特殊需求,官方建議存於外部儲存空間。
雖然是使用外部儲存空間,但因為僅供 app 自身專用,所以並不須向系統請求權限。
class MainActivity : AppCompatActivity() {
private val TAG = "MainActivity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 查詢磁碟區狀態
val sExternalStorage = Environment.getExternalStorageState()
Log.d(TAG, "可用外部空間媒體資訊: $sExternalStorage") // mounted: 可讀/寫
// 狀態有: MEDIA_UNKNOWN, MEDIA_REMOVED, MEDIA_UNMOUNTED, MEDIA_CHECKING, MEDIA_NOFS, MEDIA_MOUNTED, MEDIA_MOUNTED_READ_ONLY, MEDIA_SHARED, MEDIA_BAD_REMOVAL, MEDIA_UNMOUNTABLE
// 以前的 Android 因為 ROM 小, 多半會有 SD 卡插槽
// 現在 ROM 變大了, 也漸漸不提供 SD 卡插槽了, 並模擬出一塊虛擬 ROM
val externalStorageVolumes: Array<out File> = ContextCompat.getExternalFilesDirs(applicationContext, null)
Log.d(TAG, "可用外部空間媒體: ${externalStorageVolumes.size} 個") // 2 個, 1 個實體 SD 卡, 1 個虛擬 ROM
for(xx in externalStorageVolumes.indices) {
val primaryExternalStorage = externalStorageVolumes[xx]
Log.d(TAG, "可用外部空間 $xx: $primaryExternalStorage")
// 可用外部空間 0: /storage/emulated/0/Android/data/[您的 app 完整 package 名]/files, 虛擬 ROM 通常會是第 1 個
// 可用外部空間 1: /storage/9E1E-5F1E/Android/data/[您的 app 完整 package 名]/files, 實體 SD 卡
}
if(Environment.getExternalStorageState()==Environment.MEDIA_MOUNTED) {
// 有外部儲存空間媒體, 且可 讀/寫
// 官方強烈建議, 若沒有特殊需要, 優先使用第 1 個可用外部空間
val mFilePath = externalStorageVolumes[0]
Log.d(TAG, "mFilePath: $mFilePath") // /storage/emulated/0/Android/data/[您的 app 完整 package 名]/files
val mExtdir = File(getExternalFilesDir(null), "Chkspace")
// 查詢可用空間
val mScope = CoroutineScope(Job() + Dispatchers.IO)
mScope.launch {
var mBytes: Long = 0
// 1. 由於在 Android8(Oreo) 推出新的 API26,
// storageManager.getUuidForPath 不能在主執行緒呼叫, 因此要在 coroutine 內執行
// 2. 舊的 API 在未來會被棄用, 所以要分開處理
if(Build.VERSION.SDK_INT>=26) {
val storageManager = getSystemService(Context.STORAGE_SERVICE) as StorageManager
val uuid = storageManager.getUuidForPath(externalStorageVolumes[0])
try {
mBytes = storageManager.getAllocatableBytes(uuid)
} catch(err: IOException) {
err.printStackTrace()
}
} else {
val path = Environment.getDataDirectory()
val stat = StatFs(path.path)
val blockSize: Long = stat.blockSizeLong
val availableBlocks: Long = stat.availableBlocksLong
mBytes = availableBlocks * blockSize
}
val formatter = DecimalFormat("#,###")
Log.d(TAG, "可用剩餘外部儲存空間 = ${formatter.format(mBytes)} ")
if(mBytes>=1024) {
val mKB = (mBytes/1024) // 換算為 kb
if(mKB>=1024) {
val mmMB = (mKB/1024) // 換算為 mb
if(mmMB>=1024) {
val mGB = (mmMB/1024) // 換算為 gb
Log.d(TAG, "可用剩餘外部儲存空間 = $mGB gb")
} else
Log.d(TAG, "可用剩餘外部儲存空間 = $mmMB mb")
} else {
Log.d(TAG, "可用剩餘外部儲存空間 = $mKB kb")
}
} else {
Log.d(TAG, "可用剩餘外部儲存空間 = $mBytes bytes")
}
}
}
}
}
沒有留言:
張貼留言