Storage access framework что это
Хранение данных и файлов
В целом хранение файлов и данных можно условно разделить на две группы: во внутреннем или внешнем хранилище. Но разница между ними довольна тонка. В целом политика Гугла в отношение данных ужесточается с каждой версии системы.
Android поддерживает различные варианты хранения данных и файлов.
В зависимости от ваших потребностей, нужно выбрать нужный вариант хранения данных.
Следует быть осторожным при работе с внутренним и внешним хранилищем. Внутренне хранилище всегда есть в системе, но оно может быть не слишком большим по объёму. Вдобавок к внутреннему хранилищу, устройство может иметь внешнее хранилище. В старых моделях таким хранилищем выступала съёмная SD-карта. Сейчас чаще используют встроенную и недоступную для извлечения флеш-память. Если ваше приложение слишком большое, можно попросить систему устанавливать программу во внешнее хранилище, указав просьбу в манифесте.
В разных версиях Android требования к разрешению для работы с внешним хранилищем постоянно менялись. На данный момент (Android 10, API 29) требования выглядят следующим образом.
Приложение может иметь доступ к собственным файлам, которые находятся во внешнем хранилище. Также может получить доступ к определённым общим файлам на внешнем хранилище.
Доступ к общим файлам достигается через FileProvider API или контент-провайдеры.
Для просмотра файлов через студию используйте инструмент Device File Explorer.
Внешняя карта памяти
Попробуем немного разобраться с этим зоопарком. Но помните, что процесс путаницы продолжается.
При подготовке материала я опирался на письма некоторых читателей сайта, которые присылали свои мысли по этому поводу. Спасибо им за структуризацию материала.
Вот что я (кажется) понял, попытавшись загрузить картинку с внешней SD карточки.
External это не External
«EXTERNAL_STORAGE» называется так не потому, что это внешняя память по отношению к устройству, а потому что она выглядит как внешняя память для компьютера, если устройство подключить кабелем к компьютеру. Причём именно выглядит, потому что обмен идёт по протоколу MTP – устройство только показывает компьютеру список папок и файлов, а при необходимости открыть или скопировать файл он специально загружается на компьютер, в отличие от настоящей флешки, файлы которой становятся файлами в файловой системе самого компьютера. Обмен по MTP позволяет устройству продолжать работать, когда оно подключено к компьютеру.
Emulated это не Emulated
Сначала я пытался прочесть файл с карточки на эмуляторе (из этого так ничего и не вышло). Функция getExternalStorageDirectory() давала мне /storage/emulated/0, и я думал, что «emulated» – это потому что на эмуляторе. Но когда я подцепил реальный планшет, слово «emulated» никуда не исчезло. Я стал рыться в интернете и обнаружил, что «Emulated storage is provided by exposing a portion of internal storage through an emulation layer and has been available since Android 3.0.» – то есть это просто кусок внутренней памяти, которая путём какой-то эмуляции делается доступной для пользователя, в отличие от собственно внутренней памяти.
При этом с точки зрения системы доступная для пользователя папка называется /storage/emulated/0, а при подключении к компьютеру по USB это просто одна из двух главных папок устройства – у меня в Windows Explorer она называется Tablet. Вторая папка у меня называется Card, и это и есть настоящая внешняя карточка.
Оказалось, что несистемным приложениям в принципе запрещено напрямую обращаться к съёмной карточке! Похоже, что это было так всегда, но вот начиная с версии Android 6 Marshmallow написано: внешняя карточка может быть определена как Portable либо Adoptable. Adoptable – это как бы «усыновляемая» память которая может быть «adopted», то есть взята в систему (примерно как кот с улицы в дом – это тоже называется to adopt) и использована как внутренняя. Для этого ее надо особым образом отформатировать и не вынимать, иначе не факт, что система продолжит нормально работать.
Portable – это нормальная съёмная карточка, но несистемным приложениям запрещено обращаться из программ к файлам на ней! Вот что написано в https://source.android.com/devices/storage/traditional.html:
Android 6.0 supports portable storage devices which are only connected to the device for a short period of time, like USB flash drives. When a user inserts a new portable device, the platform shows a notification to let them copy or manage the contents of that device. In Android 6.0, any device that is not adopted is considered portable. Because portable storage is connected for only a short time, the platform avoids heavy operations such as media scanning. Third-party apps must go through the Storage Access Framework to interact with files on portable storage; direct access is explicitly blocked for privacy and security reasons.
Если я правильно понял, этот самый Storage Access Framework позволяет работать с документом на карточке через диалог (открыть файл/сохранить файл), а вот прочитать или записать файл на карточке непосредственно из программы невозможно.
Общий вывод – реально из программы можно работать только с файлами на предоставляемой пользователю части встроенной памяти устройства, а на съёмной карточке – нет.
Состояние на текущий момент
Гугл утверждает, что с версии Android 10 Q стандартный доступ к файлам будет прекращён. Ещё в Android 4.4 появился Storage Access Framework, который и должен стать заменой для работы с файлами.
Методы Environment.getExternalStorageDirectory() и Environment.getExternalStoragePublicDirectory() признаны устаревшими и будут недоступны. Даже если они будут возвращать корректные значения, ими вы не сможете воспользоваться.
В Android 7.0 добавили исключение FileUriExposedException, чтобы разработчики перестали использовать схему file://Uri.
Можно создавать файлы в корневой папке карточки при помощи Environment.getExternalStorageDirectory(), а также папки с вложенными файлами. Если папка уже существует, то у вас не будет доступа на запись (если это не ваша папка).
Если вы что-то записали, то сможете и прочитать. Чужое читать нельзя.
Кстати, разрешения на чтение и запись файлов не требуются, а READ_EXTERNAL_STORAGE и WRITE_EXTERNAL_STORAGE объявлены устаревшими.
Другие приложения не могут получить доступ к файлам вашего приложения. Файлы, которые вы создали через getExternalFilesDir(), доступны через Storage Access Framework, кроме файлов, созданных в корне карточки (что-то я совсем запутался). Ещё можно дать доступ через FileProvider.
При подключении USB-кабеля через getExternalFilesDir(), вы можете увидеть свои файлы и папки, а также файлы и папки пользователя. При этом файлы и папки пользователя на корневой папке вы не увидите. Вам не поможет даже adb или Device File Explorer студии.
Что делать?
Пользуйтесь методами класса Context, типа getExternalFilesDir(), getExternalCacheDir(), getExternalMediaDirs(), getObbDir() и им подобными, чтобы найти место для записи.
Используйте Storage Access Framework.
Используйте MediaStore для мультимедийных файлов.
Используйте FileProvider, чтобы файлы были видимы другим приложениям через ACTION_VIEW/ACTION_SEND.
Android 10: Появился новый флаг android:allowExternalStorageSandbox=»false» и метод Environment.isExternalStorageSandboxed() для работы с песочницей. Флаг android:requestLegacyExternalStorage=»true» для приложений, которые ещё используют старую модель доступа к файлам.
Как временное решение можно добавить в блок манифеста application атрибут android:requestLegacyExternalStorage=»true», чтобы доступ к файлам был как раньше в Android 4.4-9.0.
Android 11
Если вы создаёте файловый менеджер, то ему нужны возможности для просмотра файлов. Для этого следует установить разрешение MANAGE_EXTERNAL_STORAGE или использовать атрибут android:requestLegacyExternalStorage=»true» (см. выше).
Sample for Android Storage Access Framework aka Scoped Storage for Basic Use Cases.
As we all know, Google enforces their Android Security Policy changes by requiring setting targetSdkVersion aka API level in the Apps to a certain minimum. The apps that do not comply with this requirement will not be allowed to Google Play Store. Currently, minimal targetSdkVersion is 29 (Android 10), but this will change soon. As stated in the official documentation here:
One of the requirements for Api level 29 was usage of Android Storage Access Framework (SAF) instead of just getting a “WRITE_EXTERNAL_STORAGE” permission. This requirement was not enforced, though, because developers could just add android:requestLegacyExternalStorage=”true” to the App’s Manifest and use the old approach.
With the new requirement to target API level 30 old approach will not work:
So, all Apps that read or write files on the external storage will have to move the files to “internal” storage accessed by getFilesDir(), which is somewhat hard for the users to find or start using Storage Access Framework.
AFAIK, overwhelming majority of the apps, that used external storage for files other than media (audio, pics, etc) used the same pattern:
In this article I’ll try to help the developers migrate this pattern to the Storage Access Framework.
from App’s manifest. This permission is no longer needed. Than add dependency to our build.gradle:
This library contains all we need to use the SAF API.
SAF API allows users to give the App limited access to files on the device, the App receives permission to read/write to specific folders only. This permission can be persisted for later use, but should be checked every time nevertheless, since the system can revoke the permission at any time. Actually the documentation says:
App have to ask the User a permission for a folder (Document Tree as it is called in SAF documentation) that user may create:
Inside the onActivityResult the App receives the Uri of the folder that user had selected. The Uri’s scheme is content:, not file:.
The treeUri we received here is actually our goal — it points to the folder our app may use for it’s files. It can be stored as “toString” to shared preferences, and persistable permission can be taken. Thus the App will be able to use the permissions later, even after device restart. So, actually the App should first check if there is a stored Uri string in shared prefs, then check if the stored Uri string has the read/write permission and then write into the Uri.
Function arePermissionsGranted iterates through all the SAF persisted permissions for the App and checks if given Uri has permission.
It is important to remember that the amount of SAF permissions for an App is limited as CommonsWare mentioned in his blog:
The App should release persisted permissions if the User deleted or moved the folder or the permission is no longer needed.
Once the App has the treeUri either from onActivityResult or from shared preferences, and persistedPermissions are OK, it is time to use it. Make a file inside the directory:
The file here is of type androidx.documentfile.provider.DocumentFile and allows to obtain a FileOutputStream or FileInputStream like this:
So this is how we can change our App to use Storage Access Framework and be compliant with upcoming Google Play Store requirements.
Important to note that when testing on a physical device do not create files and use the file manager from Your PC to check the files at the same time. Windows file explorer might show file size of 0 Kb if the containing folder was open before the App created the file in it.
Please refer to this sample for full code:
Storage Access Framework
In this document show more show less
Key classes
Videos
Code Samples
See Also
Android 4.4 (API level 19) introduces the Storage Access Framework (SAF). The SAF makes it simple for users to browse and open documents, images, and other files across all of their their preferred document storage providers. A standard, easy-to-use UI lets users browse files and access recents in a consistent way across apps and providers.
Cloud or local storage services can participate in this ecosystem by implementing a DocumentsProvider that encapsulates their services. Client apps that need access to a provider’s documents can integrate with the SAF with just a few lines of code.
The SAF includes the following:
Some of the features offered by the SAF are as follows:
Overview
The SAF centers around a content provider that is a subclass of the DocumentsProvider class. Within a document provider, data is structured as a traditional file hierarchy:
Figure 1. Document provider data model. A Root points to a single Document, which then starts the fan-out of the entire tree.
Note the following:
Control Flow
As stated above, the document provider data model is based on a traditional file hierarchy. However, you can physically store your data however you like, as long as it can be accessed through the DocumentsProvider API. For example, you could use tag-based cloud storage for your data.
Figure 2 shows an example of how a photo app might use the SAF to access stored data:
Figure 2. Storage Access Framework Flow
Note the following:
Figure 3 shows a picker in which a user searching for images has selected a Google Drive account:
Figure 3. Picker
When the user selects Google Drive the images are displayed, as shown in figure 4. From that point on, the user can interact with them in whatever ways are supported by the provider and client app.
Figure 4. Images
Writing a Client App
On Android 4.4 and higher, you have the additional option of using the ACTION_OPEN_DOCUMENT intent, which displays a picker UI controlled by the system that allows the user to browse all files that other apps have made available. From this single UI, the user can pick a file from any of the supported apps.
This section describes how to write client apps based on the ACTION_OPEN_DOCUMENT and ACTION_CREATE_DOCUMENT intents.
Search for documents
The following snippet uses ACTION_OPEN_DOCUMENT to search for document providers that contain image files:
Note the following:
Process Results
Examine document metadata
Once you have the URI for a document, you gain access to its metadata. This snippet grabs the metadata for a document specified by the URI, and logs it:
Open a document
Once you have the URI for a document, you can open it or do whatever else you want to do with it.
Bitmap
Here is an example of how you might open a Bitmap :
Get an InputStream
Here is an example of how you can get an InputStream from the URI. In this snippet, the lines of the file are being read into a string:
Create a new document
Your app can create a new document in a document provider using the ACTION_CREATE_DOCUMENT intent. To create a file you give your intent a MIME type and a file name, and launch it with a unique request code. The rest is taken care of for you:
Delete a document
Edit a document
You can use the SAF to edit a text document in place. This snippet fires the ACTION_OPEN_DOCUMENT intent and uses the category CATEGORY_OPENABLE to to display only documents that can be opened. It further filters to show only text files:
Persist permissions
When your app opens a file for reading or writing, the system gives your app a URI permission grant for that file. It lasts until the user’s device restarts. But suppose your app is an image-editing app, and you want users to be able to access the last 5 images they edited, directly from your app. If the user’s device has restarted, you’d have to send the user back to the system picker to find the files, which is obviously not ideal.
To prevent this from happening, you can persist the permissions the system gives your app. Effectively, your app «takes» the persistable URI permission grant that the system is offering. This gives the user continued access to the files through your app, even if the device has been restarted:
There is one final step. You may have saved the most recent URIs your app accessed, but they may no longer be valid—another app may have deleted or modified a document. Thus, you should always call getContentResolver().takePersistableUriPermission() to check for the freshest data.
Writing a Custom Document Provider
If you’re developing an app that provides storage services for files (such as a cloud save service), you can make your files available through the SAF by writing a custom document provider. This section describes how to do this.
Manifest
To implement a custom document provider, add the following to your application’s manifest:
Here are excerpts from a sample manifest that includes a provider:
Supporting devices running Android 4.3 and lower
The ACTION_OPEN_DOCUMENT intent is only available on devices running Android 4.4 and higher. If you want your application to support ACTION_GET_CONTENT to accommodate devices that are running Android 4.3 and lower, you should disable the ACTION_GET_CONTENT intent filter in your manifest for devices running Android 4.4 or higher. A document provider and ACTION_GET_CONTENT should be considered mutually exclusive. If you support both of them simultaneously, your app will appear twice in the system picker UI, offering two different ways of accessing your stored data. This would be confusing for users.
Here is the recommended way of disabling the ACTION_GET_CONTENT intent filter for devices running Android version 4.4 or higher:
Contracts
Usually when you write a custom content provider, one of the tasks is implementing contract classes, as described in the Content Providers developers guide. A contract class is a public final class that contains constant definitions for the URIs, column names, MIME types, and other metadata that pertain to the provider. The SAF provides these contract classes for you, so you don’t need to write your own:
For example, here are the columns you might return in a cursor when your document provider is queried for documents or the root:
Subclass DocumentsProvider
These are the only methods you are strictly required to implement, but there are many more you might want to. See DocumentsProvider for details.
Implement queryRoots
In the following snippet, the projection parameter represents the specific fields the caller wants to get back. The snippet creates a new cursor and adds one row to it—one root, a top level directory, like Downloads or Images. Most providers only have one root. You might have more than one, for example, in the case of multiple user accounts. In that case, just add a second row to the cursor.
Implement queryChildDocuments
This method gets called when you choose an application root in the picker UI. It gets the child documents of a directory under the root. It can be called at any level in the file hierarchy, not just the root. This snippet makes a new cursor with the requested columns, then adds information about every immediate child in the parent directory to the cursor. A child can be an image, another directory—any file:
Implement queryDocument
Implement openDocument
Security
Русские Блоги
Простая адаптация к разделенному хранилищу Android 10 Scoped Storage
В Android 10 Google нацелен наВнешнее хранилищеБыла введена новая функция, ее название:Scoped Storage, Официальный перевод Google:Хранение разделов, Мы также можем назвать этоОграниченное хранилище, А почему?
В этой статье мы по-прежнему переводим его как многораздельное хранилище. Хорошо, я начну задавать вопросы!
Вопрос 1. Внешнее хранилище? Внутреннее хранилище? ОЗУ?
1.1, память
Некоторые друзья часто путают память и внутреннее хранилище, потому что внутреннее хранилище также можно для краткости называть памятью:
A: Я слышал, что вы купили новый телефон? Насколько велика память? Сколько можно открывать в фоновом режиме?
B: Ха-ха, 256G, их сотни установить не проблема!
1.2, внутренняя память
Этот путь, где 0 означает Логин пользователя (Похоже, что после Android 6.0 он поддерживает нескольких пользователей). И мы более знакомы /data/data/
в действительности /data/user/ /
Ссылка на, обратите внимание, что current_user_id 。
Этот путь применяетсяЛичный каталог внутреннего хранилища, Файлы, сохраненные по этому пути, являются личными файлами приложения, и другие приложения не могут получить доступ к этим файлам (если у них нет прав доступа Root), что очень подходит для сохранения внутренних данных приложения, к которым пользователям не нужен прямой доступ.
Когда мы удаляем приложение, файлы, сохраненные в личном пути, также будут удалены. Следовательно, мы не должны помещать те файлы данных, которые мы хотим сохранить после удаления приложения, в частный путь.
В основном это следующие часто используемые каталоги:
Полный путь: /data/data/
Полный путь: /data/data/
Полный путь: /data/data/
каталог баз данных
Полный путь: /data/data/
1,3, внешнее хранилище
Сейчас почти ни в одном телефоне Android нет гнезда для SD-карты.
1.3.1 Почему нет гнезда для SD-карты?
Я лично считаю, что есть следующие причины:
1.3.2. Означает ли невозможность вставить SD-карту, что в моем телефоне нет внешнего хранилища?
Почти все мобильные телефоны теперь имеют значительную внутреннюю емкость памяти, которая может составлять 128 ГБ, 256 ГБ, 512 ГБ в любое время, начиная со 128 ГБ, 64 ГБ почти незаметны, но 64 ГБ действительно недостаточно, личный опыт!
Система смонтирует внутреннее пространство для хранения с помощью технологии предохранителей, чтобы /storage/emulated/0 Выше эта точка монтирования является внешним хранилищем. Вы можете иметь внешнее хранилище без SD-карты. Это внешнее хранилище называется в строгом смысле слова.Встроенное внешнее хранилище, И делить пространство с внутренним хранилищем, он имеет следующие преимущества:
1.3.3. Есть ли личный каталог и общий каталог для внешнего хранилища?
Частный каталог внешнего хранилища
Да, во внешнем хранилище также есть личный каталог приложений, который строго называетсяЧастный каталог внешнего хранилища, Его путь находится по адресу: /storage/emulated/0/Android/data/
, У него также есть папка с файлами и папка кеша, используйте следующий код, чтобы получить соответствующий путь:
getExternalFilesDir() Нужен строковый параметр, если мы передадим пустую строку, мы получим /storage/emulated/0/Android/data/
Хотя эти файлы технически доступны пользователям и другим приложениям (поскольку они хранятся на внешнем хранилище), они не могут предоставить ценность пользователям вне приложения. Вы можете использовать этот каталог для хранения файлов, которыми вы не хотите делиться с другими приложениями.
Во внешнем хранилище все каталоги, кроме частных, являются общедоступными. Данные, сохраненные программой в общедоступном каталоге, останутся после удаления приложения.
Вопрос второй, на что именно влияет хранение разделов в Android 10?
Итак, Google, наконец, начал это делать и предложил в Android 10.Хранение разделов, Он предназначен для того, чтобы запретить программе делать что угодно с общедоступными каталогами во внешнем хранилище.Разделенное хранилище не влияет на частный каталог внутреннего хранилища и частный каталог внешнего хранилища.。
Короче говоря, в Android 10 нет изменений в чтении и записи частных каталогов, и набор файлов по-прежнему можно использовать без каких-либо разрешений. Для чтения и записи общедоступных каталогов вы должны использовать MediaStore Предоставляемый API или SAF (Структура доступа к хранилищу) означает, что мы больше не можем использовать набор файлов для произвольного управления общедоступными каталогами.
Приложения, использующие многораздельное хранилище, всегда имеют права на чтение и запись для файлов, созданных ими самими, независимо от того, находятся ли файлы в частном каталоге приложения. Поэтому, если ваше приложение сохраняет только файлы, созданные им самим, и получает к ним доступ, нет необходимости запрашивать READ_EXTERNAL_STORAGE Или WRITE_EXTERNAL_STORAGE Разрешения.
Для доступа к файлам, созданным другими приложениями, вам необходимо READ_EXTERNAL_STORAGE Разрешения. И все же использовать только MediaStore Предоставляемый API или SAF (Storage Access Framework) доступ.
нужно знать, MediaStore Доступ к предоставленному API возможен только: изображения, видео, аудио. Если вам нужен доступ к файлам в любом другом формате, вам необходимо использовать SAF (Структура доступа к хранилищу), он будет вызывать встроенный файловый браузер системы, чтобы пользователи могли выбирать файлы независимо.
Кажется нет WRITE_EXTERNAL_STORAGE Что случилось? Действительно, я слышал, что это разрешение будет аннулировано в будущем.
Вопрос 3. Нужно ли адаптироваться?
Если мы будем targetSdkVersion Установите значение ниже 29, чтобы наш проект мог успешно работать на телефонах Android 10 даже без какой-либо адаптации к Android 10.
Если мы будем targetSdkVersion Он установлен на 29, но я не хочу адаптироваться к хранилищу разделов. Вы можете установить следующие настройки в файле манифеста:
Вопрос 4. Неужели нельзя хранить на улице? я не верю
Сначала мы применим compileSdkVersion с участием targetSdkVersion Для обоих установлено значение 29, и программе предоставляются разрешения на чтение и запись, а затем напишите следующий код:
Код очень прост, роль заключается в создании папки с именем MyDir в корневом каталоге внешнего хранилища. Мы запустили эту программу на устройстве Android 10 и обнаружили, что она не была успешно создана ( file.mkdir().toString() для false )。
Эту же программу мы запускаем на устройствах ниже Android 10, и мы можем успешно создать эту папку.
Вопрос 5. Как мне управлять внешним хранилищем?
Теперь мы знаем, что после того, как приложение подтвердит, что оно поддерживает многораздельное хранилище, предыдущее больше не может использоваться для работы с внешним хранилищем. Что нам теперь делать? Google официально рекомендует нам использовать MediaStore Предоставить API для доступа к изображениям, видео, аудиоресурсам, использовать SAF (Storage Access Framework) Доступ к любым другим типам ресурсов.
5.1. Используйте MediaStore для сохранения изображений в каталоге изображений.
в Environment Мы можем найти имена многих общих папок каталогов, среди них Pictures Эта папка подходит для сохранения данных изображений:
В прошлом мы часто получали объект File на основе абсолютного пути к каталогу или файлу, а затем передавали объект File в FileOutputStream Получите выходной поток, и тогда вы сможете с удовольствием записывать данные. После Android 10 нам нужно записывать данные в эти общедоступные каталоги. MediaStore Вверх.
Далее мы узнаем, как сохранить растровое изображение в папку изображений с помощью кода:
Положение кода было изменено для удобства отображения.Вы можете просмотреть весь код напрямую. Адрес проекта указан в конце статьи.
Сначала мы создали ContentValues Object и добавил к нему информацию трех видов:
DISPLAY_NAME: имя изображения, которое должно включать суффикс. Здесь мы используем текущее именование меток времени
MIME_TYPE: MIME-тип файла. Здесь мы используем image/jpeg
ContentValues После того, как значения внутри установлены, мы можем использовать ContentResolver из insert() Метод вставляет данные, после завершения вставки будет получен Uri вставленного изображения, а затем мы должны получить Uri в соответствии с этим Uri OutputStream Объект, через: contentResolver.openOutputStream(uri) Вы можете получить это, остальное нужно написать Bitmap.
Мы обнаружили, что раньше мы могли получить выходной поток через реальный путь, но теперь мы можем получить его только через Uri.
Что, если мы сохраним не Bitmap в общедоступный каталог, а изображения в Интернете? На самом деле принцип тот же. Для изображений в Интернете мы определенно можем получить входной поток. Выходной поток по-прежнему получается через Uri, а затем читать входной поток и записывать выходной поток.
На этом сохранение изображений закончено, и сохранение аудио и видео аналогично. Обратите внимание, что для этих операций не требуются разрешения.
5.2. Используйте MediaStore для загрузки изображений в медиатеку.
Мы добавили файл изображения в «Картинки», как его получить? Также необходимо пройти через MediaStore. Если мы не получили разрешение на использование дискового пространства, мы можем получать изображения, созданные нашим собственным приложением, только через MediaStore; если мы получили разрешение на использование дискового пространства, мы можем получить изображения, созданные другими приложениями.
Мы узнаем через код:
Код очень прост, и, наконец, Uri файла изображения получается через комбинацию Uri и идентификатора файла изображения. После получения Uri этого изображения, как его можно отобразить? Вы можете использовать Glide, потому что Glide изначально поддерживает Uri:
Что делать, если Glide не используется? Вы можете сделать это, чтобы получить Bitmap:
Но следует отметить, что если разрешение изображения высокое, растровое изображение будет занимать память, а фактическая отображаемая область может быть намного меньше, чем исходное изображение. Вам необходимо самостоятельно контролировать пиксели растрового изображения.
Без разрешения на получение места для хранения мы можем получать только изображения, созданные самим приложением:
Ниже мы предварительно помещаем в телефон несколько изображений, чтобы имитировать их создание в других приложениях. Это следующие изображения:
Причина использования LIKE заключается в том, что абсолютный путь изображения хранится в DATA, и нам необходимо сопоставить все изображения в собственном пути изображения приложения. На этом обучение завершается получением изображений в медиатеке.
5.3. Используйте MediaStore для удаления изображений из медиатеки.
Точно так же вам не нужны какие-либо разрешения для удаления изображений, созданных вами, но вам необходимо разрешение на удаление или изменение изображений, созданных другими приложениями, и даже если у нас есть разрешения на хранение, мы не можем изменять или удалять ресурсы других приложений. MediaProvider Появится всплывающее окно, в котором пользователь сможет выбрать, разрешить ли приложению изменять или удалять изображения, видео и аудиофайлы. Результат пользовательской операции пройдет onActivityResult Обратный вызов возвращается в приложение. Если пользователь разрешит это, приложение получит разрешение на изменение uri до следующего перезапуска устройства. Давайте сначала научимся удалять изображения из наших собственных приложений:
Очень просто, картинка взята из ContentResolver Запрашивая его, мы можем получить идентификатор, а uri изображения проходит через MediaStore.Images.Media.EXTERNAL_CONTENT_URI Он совмещен с идентификатором картинки. Теперь осталось только удалить через uri. Давайте посмотрим на эффект удаления изображения, созданного приложением, когда нет разрешения на хранение. Конечно, если есть разрешение на хранение, это то же самое:
Но этот код недостаточно строг, потому что, когда мы удаляем ресурсы из других приложений, программа вылетает и выдает: RecoverableSecurityException аномальный. Следовательно, нам нужно перехватить это исключение и предложить пользователю предоставить этому uri разрешение на изменение или удаление:
На этом удаление изображений в медиатеке завершено.
Вопрос 6. Что мне делать, если я хочу прочитать некий немедиа файл в папке Download?
Возьмем для примера PDF. Очевидно, что PDF не относится к аудио, видео или изображениям, поэтому мы не можем его использовать. MediaStore Чтобы получить это. Для этого другого типа файлов мы обычно используем SAF (Storage Access Framework) Позвольте пользователям выбирать:
Примечание, ACTION_OPEN_DOCUMENT Используется для открытия файлов.
Вопрос 7. Что мне делать, если я хочу создать файл любого типа?
Вопрос 8. Что мне делать, если я хочу загрузить файл в каталог Download?
В качестве примера возьмем загрузку приложения. До Android 10 можно было получить входной поток при условии, что получен объект File. Поскольку мы адаптированы к многораздельному хранилищу в Android 10, это невозможно. MediaStore Предоставляется набор загрузок, специально используемых для выполнения операций загрузки файлов. Его использование и добавление картинок практически одинаковы:
адрес проекта
Все коды в этой статье можно посмотреть в проекте.Портал