Giới thiệu
Bài viết này hướng dẫn cách kiểm tra dung lượng bộ nhớ trống (available space) trên thiết bị Android. Sử dụng StatFs và Formatter để hiển thị dễ đọc. Phân biệt giữa Internal Storage, External Storage, và App-specific storage.
Các bước thực hiện
Bước 1: Tạo dự án mới
Mở Android Studio, chọn File → New Project và điền thông tin cần thiết.
Bước 2: Layout (res/layout/activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="16dp"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textStyle="bold"
android:textAlignment="center"
android:lineSpacingExtra="8dp" />
</LinearLayout>
Bước 3: Code kiểm tra dung lượng (src/MainActivity.java)
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Environment;
import android.os.StatFs;
import android.text.format.Formatter;
import android.util.Log;
import android.widget.TextView;
import java.io.File;
public class MainActivity extends AppCompatActivity {
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
displayStorageInfo();
}
private void displayStorageInfo() {
StringBuilder sb = new StringBuilder();
// 1. External Storage (Primary shared storage - /storage/emulated/0)
File externalStorage = Environment.getExternalStorageDirectory();
if (externalStorage != null && externalStorage.exists()) {
StatFs stat = new StatFs(externalStorage.getPath());
// API 18+ (recommended)
long totalBytes = stat.getTotalBytes();
long freeBytes = stat.getFreeBytes();
long availableBytes = stat.getAvailableBytes(); // User-accessible free space
// Legacy API (< 18)
// long blockSize = stat.getBlockSizeLong();
// long totalBlocks = stat.getBlockCountLong();
// long freeBlocks = stat.getAvailableBlocksLong();
// long totalBytes = blockSize * totalBlocks;
// long freeBytes = blockSize * freeBlocks;
sb.append("=== External Storage (Shared) ===\n");
sb.append(format("Tổng", totalBytes));
sb.append(format("Trống (hệ thống)", freeBytes));
sb.append(format("Kha dụng (user)", availableBytes));
sb.append("\n");
}
// 2. Internal Storage (App data directory - /data/data/pkg)
File internalStorage = Environment.getDataDirectory();
if (internalStorage != null && internalStorage.exists()) {
StatFs stat = new StatFs(internalStorage.getPath());
long totalBytes = stat.getTotalBytes();
long freeBytes = stat.getFreeBytes();
long availableBytes = stat.getAvailableBytes();
sb.append("=== Internal Storage (System) ===\n");
sb.append(format("Tổng", totalBytes));
sb.append(format("Trống", freeBytes));
sb.append(format("Kha dụng", availableBytes));
sb.append("\n");
}
// 3. App-specific Internal Storage (getFilesDir)
File appInternalDir = getFilesDir();
StatFs statAppInternal = new StatFs(appInternalDir.getPath());
long appInternalAvail = statAppInternal.getAvailableBytes();
sb.append("=== App Internal Storage (Private) ===\n");
sb.append(format("Kha dụng cho App", appInternalAvail));
sb.append("\n");
// 4. App-specific External Storage (getExternalFilesDir)
File appExternalDir = getExternalFilesDir(null);
if (appExternalDir != null && appExternalDir.exists()) {
StatFs statAppExternal = new StatFs(appExternalDir.getPath());
long appExternalAvail = statAppExternal.getAvailableBytes();
sb.append("=== App External Storage (Private) ===\n");
sb.append(format("Kha dụng cho App", appExternalAvail));
}
// Hiển thị dùng Formatter.formatFileSize (định dạng human-readable)
textView.setText(sb.toString());
}
private String format(String label, long bytes) {
// Formatter.formatFileSize tự động chọn KB/MB/GB
String formatted = Formatter.formatFileSize(this, bytes);
return String.format("%s: %s\n", label, formatted);
}
}
Bước 4: Manifest (androidManifest.xml)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="app.com.sample">
<!-- READ_EXTERNAL_STORAGE chỉ cần cho API ≤ 32 truy cập shared storage -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
</intent-filter>
</activity>
</application>
</manifest>
Chạy ứng dụng
Kết nối thiết bị, nhấn Run. Giao diện hiển thị dung lượng các phân vùng bộ nhớ định dạng dễ đọc (KB/MB/GB).
Phân biệt các loại dung lượng
| Phương thức StatFs (API 18+) | Ý nghĩa |
|---|---|
getTotalBytes() |
Tổng dung lượng phân vùng |
getFreeBytes() |
Dung lượng trống vật lý (có thể không ghi được do quota/permission) |
getAvailableBytes() |
Dung lượng user/app thực tế có thể ghi (khuyên dùng) |
File API đơn giản hơn (API 9+)
File path = Environment.getExternalStorageDirectory(); // Hoặc File path = getFilesDir(); // App internal long totalSpace = path.getTotalSpace(); // Tổng long freeSpace = path.getFreeSpace(); // Trống (hệ thống) long usableSpace = path.getUsableSpace(); // Kha dụng (app/user) - KHUYẾN DÙNG String formatted = Formatter.formatFileSize(context, usableSpace);
Scoped Storage (Android 10+ / API 29+)
- App chỉ truy cập được thư mục riêng:
getExternalFilesDir(),getExternalCacheDir(). - Không thể dùng
Environment.getExternalStorageDirectory()để scan toàn bộ shared storage. - Để truy cập Media (ảnh, video, audio): dùng MediaStore API.
- Để truy cập Documents/Downloads: dùng Storage Access Framework (SAF) -
ACTION_OPEN_DOCUMENT_TREE. - Quyền
READ_EXTERNAL_STORAGEkhông còn cho phép đọc file app khác từ API 30+.
Lấy tất cả Storage Volumes (API 24+)
StorageManager storageManager = getSystemService(StorageManager.class);
StorageVolume[] volumes = storageManager.getStorageVolumes();
for (StorageVolume volume : volumes) {
String uuid = volume.getUuid();
File dir = volume.getDirectory();
boolean isPrimary = volume.isPrimary();
boolean isRemovable = volume.isRemovable();
boolean isEmulated = volume.isEmulated();
long usableSpace = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
usableSpace = volume.getUsableSpace();
}
Log.d("Storage", String.format(
"Volume: %s, Primary: %b, Removable: %b, Emulated: %b, Usable: %s",
dir.getPath(), isPrimary, isRemovable, isEmulated,
Formatter.formatFileSize(this, usableSpace)
));
}
Lưu ý quan trọng
getAvailableBytes()/getUsableSpace()là chỉ số quan trọng nhất - phản ánh dung lượng app thực tế có thể ghi.- Trên Android 6.0+ (API 23), cần request runtime permission
READ_EXTERNAL_STORAGEđể truy cập shared storage (nếu targetSdkVersion ≥ 23). - Android 11+ (API 30):
MANAGE_EXTERNAL_STORAGE(All files access) cần user grant qua Settings, chỉ cho app file manager, antivirus, backup. - Không hardcode path như
/sdcard,/storage/emulated/0- dùng Environment API. - Dung lượng hiển thị cho user: luôn dùng
Formatter.formatFileSize(context, bytes).