已在 Manifest 宣告 WRITE_EXTERNAL_STORAGE 權限,但判斷 SD 卡狀態時總顯示 SDcard mounted RO (唯讀)。
String extState = Environment.getExternalStorageState();
if (!extState.equals(Environment.MEDIA_MOUNTED)) {
Log.d("TAG", "SDcard not mounted");
} else if (!extState.equals(Environment.MEDIA_MOUNTED_READ_ONLY)) { // 錯誤:邏輯反了
Log.d("TAG", "SDcard mounted RO"); // 非唯讀卻印 RO
} else {
Log.d("TAG", "SDcard mounted RW");
}
!extState.equals(MEDIA_MOUNTED_READ_ONLY) 表示「狀態**不等於**唯讀」,此時應顯示 RW (可讀寫),但代碼卻印「RO」。邏輯條件與輸出訊息不符。
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
// 可讀寫
Log.d("TAG", "SDcard mounted RW");
} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
// 唯讀
Log.d("TAG", "SDcard mounted RO");
} else if (Environment.MEDIA_UNMOUNTED.equals(state)) {
// 未掛載
Log.d("TAG", "SDcard not mounted");
} else {
// 其他狀態: MEDIA_CHECKING, MEDIA_NOFS, MEDIA_MOUNTED_READ_ONLY, MEDIA_SHARED, MEDIA_BAD_REMOVAL, MEDIA_REMOVED
Log.d("TAG", "SDcard state: " + state);
}
| 常數 | 含義 | 可讀 | 可寫 |
|---|---|---|---|
MEDIA_MOUNTED | 正常掛載 | ✓ | ✓ |
MEDIA_MOUNTED_READ_ONLY | 唯讀掛載 | ✓ | ✗ |
MEDIA_UNMOUNTED | 未掛載/移除 | ✗ | ✗ |
MEDIA_CHECKING | 檢查中 | ✗ | ✗ |
MEDIA_NOFS | 無檔案系統 | ✗ | ✗ |
MEDIA_SHARED | 作為 USB 大容量儲存共享 | ✗ | ✗ |
MEDIA_BAD_REMOVAL | 未正常移除 | ✗ | ✗ |
MEDIA_REMOVED | 物理移除 | ✗ | ✗ |
public static boolean isExternalStorageWritable() {
return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
}
public static boolean isExternalStorageReadable() {
String state = Environment.getExternalStorageState();
return Environment.MEDIA_MOUNTED.equals(state) ||
Environment.MEDIA_MOUNTED_READ_ONLY.equals(state);
}
// 取得可用的外部儲存目錄 (App 專屬,無需權限 API 19+)
public static File getAppExternalDir(Context context, String type) {
return context.getExternalFilesDir(type); // 自動處理權限、清理
}
Context.getExternalFilesDir() / getExternalCacheDir():App 專屬目錄,**無需權限**、卸載 App 自動刪除MediaStore / Storage Access Framework (ACTION_OPEN_DOCUMENT)Environment.getExternalStorageDirectory() (Android 10+ 受限)