SharedPreferences: kho lưu trữ khóa-giá trị Android là gì

Tác giả: IT Sectr Đã đăng: 2026-03-12 Thời gian đọc: 9 phút

SharedPreferences là một kho lưu trữ dữ liệu khóa-giá trị trên Android được thiết kế để lưu các cài đặt đơn giản và cấu hình ứng dụng. Dữ liệu được lưu trữ trong tệp XML trên thiết bị và chỉ có thể truy cập được trong ứng dụng đã tạo ra nó. Theo tài liệu chính thức Android Developers, 2025, SharedPreferences hỗ trợ lưu trữ các kiểu nguyên thủy: String, Int, Boolean, Float, Long và Set<String>. Đây là giải pháp đơn giản và nhanh nhất để lưu một lượng nhỏ cài đặt người dùng mà không cần truy vấn SQL hoặc làm việc trực tiếp với hệ thống tệp.

Những Điểm Chính

  • SharedPreferences — kho lưu trữ khóa-giá trị Android để lưu cài đặt ứng dụng đơn giản trong tệp XML.
  • Hỗ trợ năm kiểu dữ liệu: String, Int, Boolean, Float, Long và Set<String>.
  • Hoạt động đồng bộ (get) và không đồng bộ (apply) cho các thao tác ghi với lưu trữ trên đĩa.
  • Dữ liệu được cô lập theo tên tệp và chế độ truy cập (PRIVATE, MULTI_PROCESS).
  • Đối với khối lượng dữ liệu lớn, Google khuyến nghị sử dụng DataStore hoặc Room thay vì SharedPreferences.

SharedPreferences là gì?

SharedPreferences là một cơ chế tích hợp của Android để lưu trữ các cặp khóa-giá trị trong tệp XML trên bộ nhớ trong của thiết bị. Nó có sẵn từ API Level 1 và không yêu cầu thư viện bổ sung. Mục đích chính là lưu tùy chọn người dùng, trạng thái giao diện, cờ lần khởi chạy đầu tiên và các dữ liệu đơn giản khác không yêu cầu cơ sở dữ liệu có cấu trúc.

Mỗi tệp SharedPreferences được liên kết với một tên cụ thể và chế độ truy cập. Theo mặc định, chế độ Context.MODE_PRIVATE được sử dụng, giới hạn quyền truy cập tệp chỉ trong ứng dụng hiện tại. Trước đây Android hỗ trợ các chế độ MODE_WORLD_READABLE và MODE_WORLD_WRITEABLE, nhưng chúng đã bị không dùng nữa từ API Level 17 và bị xóa hoàn toàn trong Android 7.0 (API 24) vì lý do bảo mật.

Mặc dù đơn giản, SharedPreferences được sử dụng trong hàng triệu ứng dụng Android. Theo Google, hơn 90% ứng dụng được xuất bản trên Google Play sử dụng SharedPreferences để lưu trữ cài đặt. Tuy nhiên, đối với các tình huống phức tạp (khối lượng dữ liệu lớn, an toàn kiểu, bất đồng bộ), Google khuyến nghị các giải pháp hiện đại hơn như Preferences DataStore từ thư viện Android Jetpack.

Định dạng lưu trữ: XML trên thiết bị

Về mặt vật lý, SharedPreferences được lưu trữ dưới dạng tệp XML trong thư mục ứng dụng: /data/data/{package_name}/shared_prefs/{file_name}.xml. Tệp chứa phần tử gốc <map> với các phần tử con <string>, <int>, <boolean>, <float> và <long> tùy theo loại giá trị được lưu trữ. Kích thước tệp không bị giới hạn, nhưng đối với khối lượng dữ liệu lớn (hơn 100 KB), hiệu suất đọc và ghi bắt đầu giảm đáng kể.

Các tệp SharedPreferences không được mã hóa theo mặc định. Dữ liệu được lưu trữ dưới dạng văn bản thuần túy trên hệ thống tệp của thiết bị. Để lưu trữ dữ liệu nhạy cảm (token, mật khẩu), nên sử dụng EncryptedSharedPreferences từ thư viện AndroidX Security, tự động mã hóa khóa và giá trị bằng AES256-GCM.

SharedPreferences hoạt động như thế nào trong Android

SharedPreferences hoạt động theo nguyên tắc bộ nhớ đệm trong RAM với đồng bộ hóa đĩa định kỳ. Khi truy cập tệp lần đầu tiên (qua getSharedPreferences), Android tải tệp XML vào RAM và phân tích nó thành đối tượng Map. Tất cả các thao tác đọc tiếp theo được thực hiện từ bộ nhớ mà không cần đọc lại từ đĩa. Điều này đảm bảo tốc độ truy cập dữ liệu cao.

Các thao tác ghi sử dụng Editor — một bộ đệm thay đổi nội bộ. Khi nhà phát triển gọi putString hoặc putBoolean, các thay đổi được lưu trữ trong đối tượng Editor trong bộ nhớ. Việc ghi thực tế lên đĩa xảy ra khi phương thức commit (đồng bộ) hoặc apply (không đồng bộ) được gọi. Cho đến khi các phương thức này được gọi, dữ liệu không được lưu và nếu ứng dụng gặp sự cố bất ngờ, các thay đổi có thể bị mất.

Chế độ truy cập và ngữ cảnh

Để lấy một phiên bản SharedPreferences, hai phương thức được sử dụng: getPreferences và getSharedPreferences. Phương thức đầu tiên chỉ khả dụng trong Activity và tạo tệp có tên Activity. Phương thức thứ hai linh hoạt hơn, chấp nhận tên tệp và chế độ truy cập, và có thể truy cập từ bất kỳ ngữ cảnh nào (Application, Activity, Service). Nên sử dụng getSharedPreferences với tên tệp tương ứng với mô-đun hoặc chức năng của ứng dụng.

kotlin
// Lấy SharedPreferences
val prefs = context.getSharedPreferences(
    "user_settings", Context.MODE_PRIVATE
)

// Ghi dữ liệu
with(prefs.edit()) {
    putString("username", "Anna")
    putInt("age", 28)
    putBoolean("isLoggedIn", true)
    apply()
}

// Đọc dữ liệu
val username = prefs.getString("username", "")
val age = prefs.getInt("age", 0)
val isLoggedIn = prefs.getBoolean("isLoggedIn", false)

Khi sử dụng MODE_MULTI_PROCESS (không dùng nữa), SharedPreferences đồng bộ hóa giữa các tiến trình. Tuy nhiên, sự đồng bộ hóa này không đảm bảo tính nguyên tử và Google khuyến nghị tránh sử dụng SharedPreferences trong các tình huống đa tiến trình. Trong những trường hợp như vậy, tốt hơn nên sử dụng ContentProvider, Room với truy cập liên tiến trình hoặc DataStore.

Các phương thức chính của SharedPreferences

SharedPreferences cung cấp một tập hợp các phương thức để đọc dữ liệu theo khóa và giao diện Editor để ghi. Mỗi phương thức đọc chấp nhận hai tham số: một khóa và một giá trị mặc định được trả về nếu không tìm thấy khóa. Giá trị mặc định cũng xác định kiểu trả về: getString trả về String, getInt trả về Int, v.v.

Phương thức đọcPhương thức ghiKiểu dữ liệu
getStringputStringString
getIntputIntInt
getBooleanputBooleanBoolean
getFloatputFloatFloat
getLongputLongLong
getStringSetputStringSetSet<String>

Editor và apply so với commit

Editor là một đối tượng nội bộ của SharedPreferences thu thập các thay đổi trong bộ đệm. Sau khi thực hiện tất cả các thay đổi, nhà phát triển gọi commit() (ghi đồng bộ) hoặc apply() (ghi không đồng bộ). Sự khác biệt rất quan trọng: commit chặn luồng hiện tại cho đến khi ghi hoàn tất lên đĩa và trả về boolean (thành công/thất bại), trong khi apply thực hiện ghi trong luồng nền và trả lại quyền điều khiển ngay lập tức nhưng không trả về kết quả.

Nên sử dụng apply thay vì commit trong mọi trường hợp không cần biết kết quả ghi. apply nhanh hơn và không chặn luồng giao diện người dùng. commit chỉ nên được sử dụng khi cần biết liệu dữ liệu đã được lưu thành công hay chưa, hoặc khi làm việc với chế độ đa tiến trình. Để xóa các khóa riêng lẻ, phương thức remove được sử dụng, để xóa hoàn toàn — clear. Tất cả các thao tác xóa cũng được thực hiện qua Editor.

kotlin
// Nhiều thay đổi - một apply
prefs.edit {
    putString("theme", "dark")
    putBoolean("notifications", false)
    remove("old_key")
}

// Trình lắng nghe thay đổi giá trị
prefs.registerOnSharedPreferenceChangeListener { prefs, key ->
    Log.d("TAG", "Khóa đã thay đổi: $key")
}

Từ Android 12 (API 31), SharedPreferences đã được cải tiến với hỗ trợ registerOnSharedPreferenceChangeListener với tính năng hủy đăng ký tự động qua Lifecycle. Điều này giúp tránh rò rỉ bộ nhớ liên quan đến các trình lắng nghe bị quên. Trong các phiên bản cũ hơn, nhà phát triển phải tự gọi unregisterOnSharedPreferenceChangeListener trong onDestroy hoặc onStop của thành phần.

SharedPreferences so với các lựa chọn thay thế lưu trữ

Mặc dù được sử dụng rộng rãi, SharedPreferences không phải là giải pháp phổ quát cho mọi tình huống lưu trữ dữ liệu trên Android. Tùy thuộc vào khối lượng dữ liệu, yêu cầu an toàn kiểu và hiệu suất, Google khuyến nghị nhiều lựa chọn thay thế khác nhau có trong Android Jetpack và thư viện Android tiêu chuẩn.

Giải phápKhi nào sử dụngNhược điểm
SharedPreferencesCài đặt nhỏ (tối đa 100 khóa)Không an toàn kiểu, đọc đồng bộ
DataStoreCài đặt độ phức tạp trung bình với coroutineKhông tương thích ngược dưới API 14
RoomDữ liệu có cấu trúc và danh sáchQuá mức cho 3-5 cài đặt
EncryptedSharedPreferencesDữ liệu nhạy cảm và tokenPhụ thuộc vào AndroidX Security

DataStore — lựa chọn thay thế hiện đại

DataStore là một thư viện Android Jetpack được Google giới thiệu như một sự thay thế cho SharedPreferences. Nó cung cấp hai biến thể: Preferences DataStore (khóa-giá trị, như SharedPreferences) và Proto DataStore (lưu trữ có kiểu qua Protocol Buffers). DataStore sử dụng coroutine và Flow cho hoạt động không đồng bộ, đảm bảo an toàn kiểu và tự động xử lý di chuyển phiên bản. Google khuyến nghị DataStore cho tất cả các dự án mới.

Ưu điểm chính của DataStore là tính bất đồng bộ ở cấp độ API. Tất cả các thao tác đọc trả về Flow và các thao tác ghi là các hàm suspend. Điều này loại bỏ hoàn toàn việc chặn luồng giao diện người dùng có thể xảy ra khi đọc đồng bộ SharedPreferences. Ngoài ra, DataStore đảm bảo tính nhất quán dữ liệu: việc ghi được thực hiện trong một giao dịch và khi thất bại, tất cả các thay đổi được hoàn tác.

Ví dụ sử dụng SharedPreferences trong ứng dụng

Hãy xem xét một ví dụ thực tế: cài đặt chủ đề (sáng/tối/hệ thống) trong ứng dụng Android. Người dùng chọn một chủ đề và lựa chọn được lưu trong SharedPreferences. Khi khởi chạy ứng dụng sau đó, chủ đề được khôi phục từ cài đặt đã lưu. Để cập nhật giao diện phản ứng, việc quan sát thay đổi qua SharedPreferences.OnSharedPreferenceChangeListener được sử dụng.

Lưu cài đặt người dùng

Hãy tạo một lớp ThemePreferences đóng gói tất cả công việc với SharedPreferences cho chủ đề. Lớp này cung cấp các phương thức getTheme (đọc), setTheme (ghi) và observeTheme (quan sát). Tên tệp cài đặt sẽ là “app_preferences” với chế độ MODE_PRIVATE. Để thuận tiện, các khóa được đặt trong đối tượng companion dưới dạng hằng số.

kotlin
class ThemePreferences(context: Context) {
    companion object {
        private const val PREF_NAME = "app_preferences"
        private const val KEY_THEME = "theme_mode"
        const val THEME_LIGHT = "light"
        const val THEME_DARK = "dark"
        const val THEME_SYSTEM = "system"
    }

    private val prefs = context
        .getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)

    fun getTheme(): String =
        prefs.getString(KEY_THEME, THEME_SYSTEM) ?: THEME_SYSTEM

    fun setTheme(theme: String) {
        prefs.edit { putString(KEY_THEME, theme) }
    }

    fun observeTheme(callback: (String) -> Unit) {
        prefs.registerOnSharedPreferenceChangeListener { _, key ->
            if (key == KEY_THEME) {
                callback.invoke(getTheme())
            }
        }
    }
}

Trong Activity hoặc Fragment, việc lấy phiên bản ThemePreferences được thực hiện qua ngữ cảnh ứng dụng. Khi khởi tạo, getTheme được gọi để đặt chủ đề hiện tại. Khi người dùng chọn chủ đề mới, setTheme được gọi và qua observeTheme, giao diện được cập nhật mà không cần khởi động lại Activity. Điều quan trọng là hủy đăng ký trình lắng nghe trong onDestroy để tránh rò rỉ bộ nhớ, đặc biệt nếu Activity được tạo lại khi thay đổi cấu hình.

Đối với ứng dụng có phiên bản mục tiêu tối thiểu Android 12+, nên sử dụng registerOnSharedPreferenceChangeListener cùng với LifecycleObserver. Điều này tự động quản lý việc đăng ký và hủy đăng ký khi thay đổi vòng đời thành phần. Đối với các phiên bản cũ hơn, việc đăng ký và hủy đăng ký phải được quản lý thủ công, đây là nguồn lỗi thường gặp trong các ứng dụng sản xuất sử dụng SharedPreferences.

Câu Hỏi Thường Gặp

Có thể lưu trữ đối tượng trong SharedPreferences không?

SharedPreferences trực tiếp chỉ hỗ trợ các kiểu nguyên thủy và Set<String>. Để lưu trữ đối tượng, cần tuần tự hóa chúng thành chuỗi JSON qua Gson hoặc Moshi, lưu qua putString và giải tuần tự hóa khi đọc. Đối với các đối tượng phức tạp có nhiều trường, nên sử dụng Room thay vì SharedPreferences với tuần tự hóa JSON.

SharedPreferences có an toàn cho luồng không?

Có, SharedPreferences an toàn cho luồng. Tất cả các thao tác đọc và ghi được đồng bộ hóa ở cấp độ đối tượng SharedPreferences và Editor của nó. Tuy nhiên, khi sử dụng chế độ đa tiến trình, việc đồng bộ hóa không được đảm bảo. Đối với truy cập đồng thời từ nhiều luồng trong cùng một ứng dụng, SharedPreferences an toàn mà không cần khóa bổ sung.

Làm thế nào để xóa tất cả dữ liệu SharedPreferences?

Để xóa hoàn toàn tất cả dữ liệu khỏi SharedPreferences, hãy gọi phương thức clear() trên Editor và áp dụng các thay đổi qua apply. Nếu cần xóa chính tệp XML, hãy sử dụng deleteSharedPreferences(name) trên ngữ cảnh. Xóa dữ liệu ứng dụng qua Cài đặt → Ứng dụng → Xóa dữ liệu cũng xóa tất cả các tệp SharedPreferences.

SharedPreferences hay DataStore: nên chọn cái nào?

Đối với các dự án mới, Google khuyến nghị DataStore như một sự thay thế cho SharedPreferences. DataStore cung cấp hoạt động không đồng bộ với coroutine, an toàn kiểu (Proto DataStore) và di chuyển tự động. SharedPreferences chỉ nên được chọn cho các dự án có phiên bản tối thiểu dưới API 14 hoặc khi cần tích hợp nhanh mà không có phụ thuộc bổ sung.

Làm thế nào để mã hóa dữ liệu trong SharedPreferences?

Để mã hóa dữ liệu, hãy sử dụng EncryptedSharedPreferences từ thư viện AndroidX Security. Nó tự động mã hóa khóa và giá trị bằng AES-256 GCM. Quy trình thiết lập rất đơn giản: getSharedPreferences được thay thế bằng EncryptedSharedPreferences.create với việc chỉ định khóa chính từ Android Keystore.

Tổng Kết

  • SharedPreferences — kho lưu trữ khóa-giá trị tích hợp của Android để lưu cài đặt ứng dụng đơn giản ở định dạng XML.
  • Hỗ trợ sáu kiểu dữ liệu: String, Int, Boolean, Float, Long và Set<String> với chỉ định giá trị mặc định.
  • Các thao tác đọc được thực hiện từ bộ nhớ (bộ đệm), ghi — qua Editor với commit đồng bộ hoặc apply không đồng bộ.
  • Dữ liệu được cô lập theo tên tệp và chế độ MODE_PRIVATE, chỉ có thể truy cập trong ứng dụng đã tạo.
  • Để lưu trữ dữ liệu nhạy cảm, hãy sử dụng EncryptedSharedPreferences với mã hóa AES-256.
  • Đối với các dự án mới, Google khuyến nghị DataStore như một lựa chọn thay thế không đồng bộ hiện đại với coroutine và Flow.
  • SharedPreferences vẫn là lựa chọn tốt nhất để lưu nhanh 5–50 cài đặt đơn giản mà không có phụ thuộc bổ sung.

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm