Để mang lại cho người dùng nhiều quyền kiểm soát hơn đối với tệp của họ và hạn chế tình trạng tệp lộn xộn, Android 10 đã cho ra mắt một mô hình bộ nhớ mới cho các ứng dụng có tên là bộ nhớ có giới hạn. Bộ nhớ có giới hạn thay đổi cách ứng dụng lưu trữ và truy cập vào các tệp trên bộ nhớ ngoài của thiết bị. Để giúp bạn di chuyển ứng dụng của mình nhằm hỗ trợ bộ nhớ có giới hạn, hãy làm theo các phương pháp hay nhất dành cho những trường hợp sử dụng bộ nhớ phổ biến được nêu trong hướng dẫn này. Các trường hợp sử dụng được sắp xếp theo hai danh mục: xử lý các tệp đa phương tiện và xử lý các tệp không phải đa phương tiện.
Để tìm hiểu thêm về cách lưu trữ và truy cập vào các tệp trên Android, hãy xem hướng dẫn huấn luyện về bộ nhớ.
Xử lý các tệp đa phương tiện
Mục này mô tả một số trường hợp sử dụng phổ biến khi xử lý các tệp đa phương tiện (tệp video, hình ảnh và âm thanh) và giải thích tổng quát cách tiếp cận ứng dụng của bạn có thể sử dụng. Bảng sau đây tóm tắt từng trường hợp sử dụng trong số này và liên kết đến từng phần cung cấp thêm thông tin chi tiết.
Trường hợp sử dụng | Tóm tắt |
---|---|
Hiển thị tất cả các tệp hình ảnh hoặc video | Sử dụng cùng một phương pháp cho tất cả các phiên bản Android. |
Hiển thị hình ảnh hoặc video từ một thư mục cụ thể | Sử dụng cùng một phương pháp cho tất cả các phiên bản Android. |
Truy cập thông tin vị trí từ ảnh | Sử dụng một phương pháp nếu ứng dụng của bạn sử dụng bộ nhớ có giới hạn. Sử dụng một phương pháp khác nếu ứng dụng của bạn chọn không sử dụng bộ nhớ có giới hạn. |
Xác định vị trí bộ nhớ cho các tệp mới tải xuống | Sử dụng một phương pháp nếu ứng dụng của bạn sử dụng bộ nhớ có giới hạn. Sử dụng một phương pháp khác nếu ứng dụng của bạn chọn không sử dụng bộ nhớ có giới hạn. |
Xuất các tệp đa phương tiện của người dùng sang một thiết bị | Sử dụng cùng một phương pháp cho tất cả các phiên bản Android. |
Sửa đổi hoặc xoá nhiều tệp đa phương tiện trong một thao tác | Sử dụng một phương pháp dành cho Android 11. Đối với Android 10, hãy chọn không dùng bộ nhớ có giới hạn và dùng phương pháp này cho Android 9 trở xuống. |
Nhập một hình ảnh đã tồn tại | Sử dụng cùng một phương pháp cho tất cả các phiên bản Android. |
Chụp một hình ảnh | Sử dụng cùng một phương pháp cho tất cả các phiên bản Android. |
Chia sẻ tệp đa phương tiện với các ứng dụng khác | Sử dụng cùng một phương pháp cho tất cả các phiên bản Android. |
Chia sẻ tệp đa phương tiện với một ứng dụng cụ thể | Sử dụng cùng một phương pháp cho tất cả các phiên bản Android. |
Truy cập tệp từ mã hoặc thư viện sử dụng đường dẫn tệp trực tiếp | Sử dụng một phương pháp dành cho Android 11. Đối với Android 10, hãy chọn không dùng bộ nhớ có giới hạn và dùng phương pháp này cho Android 9 trở xuống. |
Hiển thị các tệp hình ảnh hoặc video từ nhiều thư mục
Truy vấn một bộ sưu tập đa phương tiệnbằng API query()
. Để lọc hoặc sắp xếp các tệp đa phương tiện, hãy điều chỉnh các tham số projection
, selection
, selectionArgs
và sortOrder
.
Hiển thị hình ảnh hoặc video từ một thư mục cụ thể
Sử dụng phương pháp sau:
- Làm theo các phương pháp hay nhất nêu trong phần Yêu cầu quyền cho ứng dụng, yêu cầu quyền
READ_EXTERNAL_STORAGE
. - Truy xuất tệp đa phương tiện dựa trên giá trị của
MediaColumns.DATA
, chứa đường dẫn hệ thống tệp tuyệt đối đến mục phương tiện trên ổ đĩa.
Lưu ý: Khi truy cập vào một tệp đa phương tiện hiện có, bạn có thể sử dụng giá trị của cột DATA
trong logic của mình. Đó là vì giá trị này có một đường dẫn tệp hợp lệ.
Tuy nhiên, đừng cho rằng tệp đó luôn có sẵn. Hãy chuẩn bị để sẵn sàng xử lý mọi lỗi I/O dựa trên tệp có thể xảy ra.
Mặt khác, để tạo hoặc cập nhật một tệp đa phương tiện, đừng sử dụng cột DATA
. Thay vào đó, hãy sử dụng cột DISPLAY_NAME
và RELATIVE_PATH
.
Truy cập vào thông tin vị trí từ ảnh
Nếu ứng dụng của bạn sử dụng bộ nhớ có giới hạn, hãy làm theo các bước trong phần Thông tin vị trí trong ảnh chụp của hướng dẫn về bộ nhớ phương tiện.
Xác định vị trí bộ nhớ cho các tệp mới tải xuống
Nếu ứng dụng của bạn sử dụng bộ nhớ có giới hạn, hãy lưu ý vị trí bạn chọn lưu các tệp đa phương tiện mà bạn tải xuống.
Nếu các ứng dụng khác yêu cầu quyền truy cập vào tệp, hãy cân nhắc sử dụng bộ sưu tập đa phương tiện được xác định rõ cho tệp tải xuống hoặc bộ sưu tập tài liệu.
Trên Android 11 trở lên, các ứng dụng khác không thể truy cập vào các tệp bên trong thư mục dành riêng cho ứng dụng bên ngoài, ngay cả khi bạn sử dụng DownloadManager
để tìm nạp các tệp này.
Xuất các tệp đa phương tiện của người dùng sang một thiết bị
Xác định vị trí mặc định thích hợp để lưu trữ tệp đa phương tiện của người dùng:
- Cho phép người dùng chọn xem có cho phép các ứng dụng khác đọc các tệp đa phương tiện của họ hay không, thông qua bộ nhớ dành riêng cho ứng dụng hoặc bộ nhớ dùng chung.
- Cho phép người dùng xuất tệp từ thư mục dành riêng cho ứng dụng sang vị trí thường dễ truy cập hơn. Hãy sử dụng các bộ sưu tập hình ảnh, video và âm thanh của MediaStore để xuất các tệp đa phương tiện vào thư viện của thiết bị.
Sửa đổi hoặc xoá nhiều tệp đa phương tiện trong một thao tác
Kết hợp logic dựa trên các phiên bản Android mà ứng dụng của bạn chạy.
Chạy trên Android 11
Sử dụng phương pháp sau:
- Tạo một ý định đang chờ xử lý cho yêu cầu ghi hoặc xoá của ứng dụng bằng
MediaStore.createWriteRequest()
hoặcMediaStore.createTrashRequest()
rồi nhắc người dùng cấp quyền chỉnh sửa tập hợp tệp bằng cách gọi ý định đó. Đánh giá phản hồi của người dùng:
- Nếu quyền đã được cấp, hãy tiến hành sửa đổi hoặc xoá thao tác.
- Nếu quyền chưa được cấp, hãy giải thích cho người dùng về lý do tính năng trong ứng dụng của bạn cần quyền đó.
Tìm hiểu thêm về cách quản lý các nhóm tệp đa phương tiện bằng các phương thức có trên Android 11 trở lên này.
Chạy trên Android 10
Nếu ứng dụng của bạn nhắm đến Android 10 (API cấp 29), hãy chọn không sử dụng bộ nhớ có giới hạn và tiếp tục sử dụng phương pháp cho Android 9 trở xuống để thực hiện thao tác này.
Chạy trên Android 9 trở xuống
Sử dụng phương pháp sau:
- Làm theo các phương pháp hay nhất nêu trong phần Yêu cầu quyền cho ứng dụng, yêu cầu quyền
WRITE_EXTERNAL_STORAGE
. - Dùng API
MediaStore
để sửa đổi hoặc xoá các tệp đa phương tiện.
Nhập một hình ảnh đã tồn tại
Khi bạn muốn nhập một hình ảnh đã tồn tại (ví dụ: để sử dụng làm ảnh hồ sơ của người dùng), ứng dụng của bạn có thể sử dụng giao diện người dùng riêng cho thao tác hoặc có thể sử dụng bộ chọn hệ thống.
Trình bày giao diện người dùng của riêng bạn
Sử dụng phương pháp sau:
- Làm theo các phương pháp hay nhất nêu trong phần Yêu cầu quyền cho ứng dụng, yêu cầu quyền
READ_EXTERNAL_STORAGE
. - Dùng API
query()
để truy vấn bộ sưu tập đa phương tiện. - Hiển thị các kết quả trong giao diện người dùng tuỳ chỉnh của ứng dụng.
Sử dụng bộ chọn hệ thống
Sử dụng ý định ACTION_GET_CONTENT
, yêu cầu người dùng chọn một hình ảnh cần nhập.
Nếu muốn lọc các loại hình ảnh mà bộ chọn hệ thống hiển thị để người dùng lựa chọn, bạn có thể sử dụng setType()
hoặc EXTRA_MIME_TYPES
.
Chụp một hình ảnh
Khi bạn muốn chụp một hình ảnh để dùng trong ứng dụng của mình (ví dụ: dùng làm ảnh hồ sơ của người dùng), hãy sử dụng ý định
ACTION_IMAGE_CAPTURE
để yêu cầu người dùng chụp ảnh bằng máy ảnh của thiết bị. Hệ thống lưu trữ ảnh đã chụp trong bảng MediaStore.Images
.
Chia sẻ tệp đa phương tiện với các ứng dụng khác
Sử dụng phương thức insert()
để thêm các bản ghi trực tiếp vào MediaStore. Để biết thêm thông tin, xem phần Thêm mục trong hướng dẫn về bộ nhớ phương tiện.
Chia sẻ tệp đa phương tiện với một ứng dụng cụ thể
Sử dụng thành phần FileProvider
của Android, như mô tả trong hướng dẫn Thiết lập tính năng chia sẻ tệp.
Truy cập các tệp từ mã hoặc thư viện sử dụng đường dẫn tệp trực tiếp
Kết hợp logic dựa trên các phiên bản Android mà ứng dụng của bạn chạy.
Chạy trên Android 11
Sử dụng phương pháp sau:
- Làm theo các phương pháp hay nhất nêu trong phần Yêu cầu quyền cho ứng dụng, yêu cầu quyền
READ_EXTERNAL_STORAGE
. - Truy cập các tệp bằng đường dẫn tệp trực tiếp.
Để biết thêm thông tin, hãy xem phần về cách mở tệp đa phương tiện bằng đường dẫn tệp trực tiếp.
Chạy trên Android 10
Nếu ứng dụng của bạn nhắm đến Android 10 (API cấp 29), hãy chọn không sử dụng bộ nhớ có giới hạn và tiếp tục sử dụng phương pháp cho Android 9 trở xuống để thực hiện thao tác này.
Chạy trên Android 9 trở xuống
Sử dụng phương pháp sau:
- Làm theo các phương pháp hay nhất nêu trong phần Yêu cầu quyền cho ứng dụng, yêu cầu quyền
WRITE_EXTERNAL_STORAGE
. - Truy cập các tệp bằng đường dẫn tệp trực tiếp.
Xử lý các tệp không phải phương tiện
Mục này mô tả một số trường hợp sử dụng phổ biến khi xử lý các tệp không phải phương tiện và giải thích phương pháp cấp cao mà ứng dụng của bạn có thể sử dụng. Bảng sau đây tóm tắt từng trường hợp sử dụng trong số này và liên kết đến từng phần cung cấp thêm thông tin chi tiết.
Trường hợp sử dụng | Tóm tắt |
---|---|
Mở một tệp tài liệu | Sử dụng cùng một phương pháp cho tất cả các phiên bản Android. |
Ghi vào tệp trên phương tiện bộ nhớ phụ | Sử dụng một phương pháp dành cho Android 11. Sử dụng một phương pháp khác cho các phiên bản Android cũ hơn. |
Di chuyển các tệp hiện có từ một vị trí lưu trữ cũ | Di chuyển tệp sang bộ nhớ có giới hạn khi có thể. Chọn không sử dụng bộ nhớ có giới hạn cho Android 10 khi cần thiết. |
Chia sẻ nội dung với các ứng dụng khác | Sử dụng cùng một phương pháp cho tất cả các phiên bản Android. |
Lưu các tệp không phải phương tiện vào bộ nhớ đệm | Sử dụng cùng một phương pháp cho tất cả các phiên bản Android. |
Xuất các tệp không phải phương tiện sang một thiết bị | Sử dụng một phương pháp nếu ứng dụng của bạn sử dụng bộ nhớ có giới hạn. Sử dụng một phương pháp khác nếu ứng dụng của bạn chọn không sử dụng bộ nhớ có giới hạn. |
Mở một tệp tài liệu
Sử dụng ý định ACTION_OPEN_DOCUMENT
để yêu cầu người dùng chọn một tệp cần mở bằng bộ chọn hệ thống. Nếu muốn lọc các loại tệp mà bộ chọn hệ thống sẽ hiển thị để người dùng chọn, bạn có thể sử dụng
setType()
hoặc EXTRA_MIME_TYPES
.
Ví dụ: Bạn có thể tìm thấy tất cả các tệp PDF, ODT và TXT bằng mã sau:
Kotlin
startActivityForResult( Intent(Intent.ACTION_OPEN_DOCUMENT).apply { addCategory(Intent.CATEGORY_OPENABLE) type = "*/*" putExtra(Intent.EXTRA_MIME_TYPES, arrayOf( "application/pdf", // .pdf "application/vnd.oasis.opendocument.text", // .odt "text/plain" // .txt )) }, REQUEST_CODE )
Java
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("*/*"); intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[] { "application/pdf", // .pdf "application/vnd.oasis.opendocument.text", // .odt "text/plain" // .txt }); startActivityForResult(intent, REQUEST_CODE);
Ghi vào các tệp trên các phương tiện bộ nhớ phụ
Phương tiện bộ nhớ phụ gồm cả thẻ SD. Bạn có thể truy cập thông tin về phương tiện bộ nhớ nhất định bằng cách sử dụng lớp
StorageVolume
.
Kết hợp logic dựa trên phiên bản Android mà ứng dụng của bạn chạy.
Chạy trên Android 11
Sử dụng phương pháp sau:
- Sử dụng mô hình bộ nhớ có giới hạn.
- Nhắm mục tiêu đến Android 10 (API cấp 29) trở xuống.
- Khai báo quyền
WRITE_EXTERNAL_STORAGE
. - Thực hiện một trong các loại quyền truy cập sau:
- Quyền truy cập vào tệp bằng API
MediaStore
. - Quyền truy cập vào đường dẫn tệp trực tiếp bằng các API, chẳng hạn như
File
hoặcfopen()
.
- Quyền truy cập vào tệp bằng API
Chạy trên các phiên bản cũ hơn
Sử dụng Khung truy cập bộ nhớ (Storage Access Framework), cho phép người dùng chọn vị trí trên một phương tiện bộ nhớ phụ mà ứng dụng của bạn có thể ghi tệp.
Di chuyển các tệp hiện có từ một vị trí bộ nhớ cũ
Một thư mục được coi là vị trí bộ nhớ cũ nếu không phải là thư mục dành riêng cho ứng dụng hoặc thư mục dùng chung công khai. Nếu ứng dụng của bạn tạo hoặc sử dụng các tệp ở vị trí bộ nhớ cũ, thì bạn nên di chuyển các tệp của ứng dụng sang những vị trí mà bộ nhớ có giới hạn có thể truy cập và thực hiện mọi thay đổi cần thiết để ứng dụng tương tác với các tệp trong bộ nhớ có giới hạn.
Duy trì quyền truy cập vào vị trí bộ nhớ cũ để di chuyển dữ liệu
Ứng dụng của bạn cần duy trì quyền truy cập vào vị trí bộ nhớ cũ để di chuyển mọi tệp ứng dụng sang những vị trí mà bộ nhớ có giới hạn có thể truy cập được. Phương pháp mà bạn nên sử dụng phụ thuộc vào cấp độ API mục tiêu của ứng dụng.
Nếu ứng dụng của bạn nhắm mục tiêu Android 11
Đặt cờ
preserveLegacyExternalStorage
thànhtrue
nhằm duy trì mô hình bộ nhớ cũ để ứng dụng của bạn có thể di chuyển dữ liệu của người dùng khi họ nâng cấp lên phiên bản ứng dụng mới nhắm mục tiêu đến Android 11.Tiếp tục chọn không sử dụng bộ nhớ có giới hạn để ứng dụng có thể tiếp tục truy cập vào các tệp của bạn ở vị trí bộ nhớ cũ trên các thiết bị Android 10.
Nếu ứng dụng của bạn nhắm mục tiêu đến Android 10
Chọn không sử dụng bộ nhớ có giới hạn để giúp dễ dàng duy trì hành vi của ứng dụng trên các phiên bản Android.
Di chuyển dữ liệu ứng dụng
Khi ứng dụng của bạn đã sẵn sàng di chuyển, hãy sử dụng phương pháp sau:
- Nhắm mục tiêu đến Android 10 trở xuống.
- Chọn không sử dụng bộ nhớ có giới hạn để ứng dụng của bạn có quyền truy cập vào các tệp mà bạn cần di chuyển.
-
Triển khai mã sử dụng API
File
để di chuyển các tệp từ vị trí hiện tại của những tệp đó trong/sdcard/
sang một vị trí có thể truy cập được bằng bộ nhớ có giới hạn:- Di chuyển mọi tệp ứng dụng riêng tư sang thư mục mà phương thức
getExternalFilesDir()
trả về. - Di chuyển mọi tệp không phải phương tiện đã chia sẻ sang một thư mục con dành riêng cho ứng dụng của thư mục
Downloads/
.
- Di chuyển mọi tệp ứng dụng riêng tư sang thư mục mà phương thức
- Xoá các thư mục bộ nhớ cũ của ứng dụng khỏi thư mục
/sdcard/
.
Sau khi người dùng cài đặt phiên bản mới của ứng dụng, họ sẽ hoàn tất quá trình di chuyển dữ liệu trên thiết bị của mình. Bạn có thể theo dõi quá trình di chuyển trong cơ sở người dùng bằng cách tạo một sự kiện (event) phân tích.
Khi người dùng đã di chuyển dữ liệu của họ, phát hành một bản cập nhật khác cho ứng dụng của bạn, trong ứng dụng này bạn nhắm mục tiêu đến Android 11.
Chia sẻ nội dung với các ứng dụng khác
Để chia sẻ các tệp của ứng dụng với một ứng dụng khác, hãy sử dụng
FileProvider
. Đối với các ứng dụng cần chia sẻ tệp với nhau, bạn nên sử dụng nhà cung cấp nội dung cho từng ứng dụng, sau đó đồng bộ hoá dữ liệu khi các ứng dụng được thêm vào bộ sưu tập.
Lưu các tệp không phải phương tiện vào bộ nhớ đệm
Phương thức bạn nên sử dụng phụ thuộc vào loại tệp bạn cần lưu vào bộ nhớ đệm.
- Tệp nhỏ hoặc tệp chứa thông tin nhạy cảm: Sử dụng
Context#getCacheDir()
. - Tệp lớn hoặc tệp không chứa thông tin nhạy cảm: Sử dụng
Context#getExternalCacheDir()
.
Xuất các tệp không phải phương tiện sang một thiết bị
Xác định vị trí mặc định thích hợp để lưu trữ các tệp không phải phương tiện. Cho phép người dùng xuất tệp từ thư mục dành riêng cho ứng dụng sang vị trí thường dễ truy cập hơn. Sử dụng các tệp đã tải xuống hoặc bộ sưu tập tài liệu của MediaStore để xuất các tệp không phải phương tiện sang thiết bị.
Tạm thời chọn không sử dụng bộ nhớ có giới hạn
Trước khi ứng dụng của bạn hoàn toàn tương thích với bộ nhớ có giới hạn, bạn có thể tạm thời chọn không sử dụng, cả trong các kiểm thử và trong ứng dụng phát hành chính thức của bạn.
Chọn không tham gia trong kiểm thử
Trên Android 10 (API cấp 29) trở lên, theo mặc định, kiểm thử của ứng dụng sẽ chạy trong hộp cát bộ nhớ. Hộp cát này ngăn ứng dụng truy cập vào các tệp bên ngoài thư mục dành riêng cho ứng dụng và các thư mục được chia sẻ công khai.
Nếu một kiểm thử xuất ra các tệp cho máy chủ lưu trữ – chẳng hạn như ảnh chụp màn hình, dữ liệu gỡ lỗi, dữ liệu về độ bao phủ hoặc chỉ số về hiệu suất, thì bạn có thể ghi các tệp này vào thư mục chung. Để làm như vậy, hãy thêm cờ sau đây vào phần khai thác liên quan gọi
am instrument
:
-e no-isolated-storage 1
Cờ này ảnh hưởng đến tất cả hành vi của trường hợp kiểm thử được đo lường và cũng ảnh hưởng đến tất cả các mã kiểm thử được gọi. Do đó, khi sử dụng cờ này, bạn không thể xác thực khả năng tương thích của ứng dụng với bộ nhớ có giới hạn. Đối với đầu ra kiểm thử, tốt hơn là bạn nên ghi vào bộ nhớ có giới hạn trong ứng dụng mà lệnh sell có thể đọc được. Sau đó, bạn có thể kéo (pull) thư mục có giới hạn trong ứng dụng đó. Để xác định thư mục mà từ đó bạn muốn kéo, hãy gọi
getExternalMediaDirs()
.
Chọn không sử dụng trong ứng dụng phát hành chính thức
Nếu ứng dụng của bạn nhắm mục tiêu đến Android 10 (API cấp 29) trở xuống, bạn có thể tạm thời chọn không sử dụng bộ nhớ có giới hạn trong ứng dụng phát hành chính thức. Tuy nhiên, nếu nhắm mục tiêu đến Android 10, bạn cần đặt giá trị của requestLegacyExternalStorage
thành true
trong tệp kê khai của ứng dụng:
<manifest ... > <!-- This attribute is "false" by default on apps targeting Android 10. --> <application android:requestLegacyExternalStorage="true" ... > ... </application> </manifest>
Để kiểm thử cách một ứng dụng nhắm mục tiêu đến Android 10 trở xuống hoạt động khi sử dụng bộ nhớ có giới hạn, bạn có thể chọn tham gia hành vi bằng cách đặt giá trị
requestLegacyExternalStorage
thành false
. Nếu đang kiểm thử trên một thiết bị chạy Android 11, bạn cũng có thể sử dụng cờ tương thích của ứng dụng để kiểm thử hành vi của ứng dụng có hoặc không có bộ nhớ có giới hạn.
Tài nguyên khác
Để biết thêm thông tin về bộ nhớ Android, hãy xem các tài liệu sau: