Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Android

Lấy dung lượng bộ nhớ trống (Internal/External) trên Android

Giới thiệu

Bài viết này hướng dẫn cách lấy dung lượng bộ nhớ trống (free space) của bộ nhớ nội bộ (internal) và bộ nhớ ngoài (external/SD card) trên Android. Sử dụng StatFs (API 1+) hoặc File.getUsableSpace() (API 9+).

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: Thiết kế giao diện (res/layout/activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:lineSpacingExtra="8dp" />

</LinearLayout>

Bước 3: Viết code lấy 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.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. Internal Storage (App-specific)
        File internalDir = getFilesDir();
        sb.append("=== Internal Storage (App private) ===\n");
        sb.append(formatStorage(internalDir));
        sb.append("\n");

        // 2. Internal Storage (Total - API 9+)
        File internalRoot = Environment.getDataDirectory();
        sb.append("=== Internal Storage (Total) ===\n");
        sb.append(formatStorage(internalRoot));
        sb.append("\n");

        // 3. External Storage (Primary shared/storage/emulated/0)
        File externalDir = Environment.getExternalStorageDirectory();
        sb.append("=== External Storage (Primary) ===\n");
        sb.append(formatStorage(externalDir));
        sb.append("\n");

        // 4. External Storage (App-specific - không cần permission)
        File externalAppDir = getExternalFilesDir(null);
        if (externalAppDir != null) {
            sb.append("=== External Storage (App private) ===\n");
            sb.append(formatStorage(externalAppDir));
        }

        textView.setText(sb.toString());
    }

    private String formatStorage(File path) {
        if (path == null || !path.exists()) {
            return "Path không tồn tại";
        }

        // Cách 1: File API (API 9+) - đơn giản, khuyên dùng
        long totalBytes = path.getTotalSpace();
        long freeBytes = path.getFreeSpace();
        long usableBytes = path.getUsableSpace(); // Dung lượng app thực tế có thể dùng

        // Cách 2: StatFs (API 1+) - chi tiết hơn, cho thiết bị cũ
        // StatFs stat = new StatFs(path.getPath());
        // long blockSize = stat.getBlockSizeLong();
        // long totalBlocks = stat.getBlockCountLong();
        // long freeBlocks = stat.getAvailableBlocksLong();
        // long totalBytes = blockSize * totalBlocks;
        // long freeBytes = blockSize * freeBlocks;

        return String.format(
            "Tổng: %s\nTrống: %s\nKha dụng: %s",
            formatBytes(totalBytes),
            formatBytes(freeBytes),
            formatBytes(usableBytes)
        );
    }

    private String formatBytes(long bytes) {
        if (bytes < 1024) return bytes + " B";
        int exp = (int) (Math.log(bytes) / Math.log(1024));
        String unit = "KMGTPE".charAt(exp - 1) + "B";
        return String.format("%.2f %s", bytes / Math.pow(1024, exp), unit);
    }
}

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">

    <!-- Không cần permission READ_EXTERNAL_STORAGE cho getExternalFilesDir() -->
    <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 tổng, trống, kha dụng của các phân vùng bộ nhớ.

Giải thích các khái niệm bộ nhớ

Loại bộ nhớ Đường dẫn típ Quyền cần Đặc điểm
Internal (App private) /data/user/0/package.name/files Không cần App riêng, bị xóa khi uninstall, an toàn nhất
Internal (System) /data Root Toàn bộ phân vùng hệ thống
External (Primary/Shared) /storage/emulated/0 READ_EXTERNAL_STORAGE (API ≤ 32) Chung cho user, media, download, documents
External (App private) /storage/emulated/0/Android/data/pkg Không cần App riêng trên external, bị xóa khi uninstall
Removable SD Card /storage/xxxx-xxxx READ_EXTERNAL_STORAGE + SAF Thẻ nhớ vật lý, cần Storage Access Framework

Thay đổi theo phiên bản Android

  • API 19 (KitKat): App có thể ghi vào getExternalFilesDir() không cần permission.
  • API 29 (Android 10): Scoped Storage - giới hạn truy cập external shared storage. Dùng MediaStore, SAF.
  • API 30 (Android 11): READ_EXTERNAL_STORAGE không cho truy cập thư mục app khác. Chỉ MediaStore/SAF.
  • API 33 (Android 13): Granular media permissions (READ_MEDIA_IMAGES, READ_MEDIA_VIDEO, READ_MEDIA_AUDIO).

Cách hiện đại: StorageManager (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();
    
    // Lấy usable space
    long usableBytes = 0;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        usableBytes = volume.getUsableSpace();
    }
    // ...
}

Lưu ý quan trọng

  • getFreeSpace() vs getUsableSpace(): Usable space tính đến giới hạn quota cho app (thường < free space).
  • Không hardcode đường dẫn /sdcard - dùng Environment.getExternalStorageDirectory().
  • Trên Android 10+, ưu tiên dùng getExternalFilesDir(), MediaStore, Storage Access Framework.
  • Dung lượng hiển thị cho user nên dùng Formatter.formatFileSize(context, bytes).