Storage Access Framework Получение правильного пути Uri Удалить / Редактировать / Получить файл
TL:DR; Я объяснил, как использовать создание папок и подпапок с помощью DocumentFile и как удалить файл, созданный с помощью этого класса. Uri, возвращаемый из onActvityResult() и documentFile.getUri.toString(), не совпадают. Мой вопрос заключается в том, как получить действительный Uri для работы с папками и файлами без использования SAF UI, если возможно, без использования хака.
Позвольте мне поделиться тем, что я узнал до сих пор, и задать свои вопросы. Если вы хотите получить Uri папки и работать над ним, вы должны использовать Intent
с ACTION_OPEN_DOCUMENT_TREE
чтобы получить Uri для доступа к папкам и установить разрешение W / R для этого URI.
Персистируемое разрешение предоставлено onActivityResult с:
final int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
// Check for the freshest data.
getContentResolver().takePersistableUriPermission(treeUri, takeFlags);
Если вы выберете основную папку устройства:
Uri treeUri = data.getData();
treeUri.toString()
Возвращает: content: //com.android.externalstorage.documents/tree/primary:
File mediaStorageDir = new File(Environment.getExternalStorageDirectory(), "");
Возвращает: хранение / эмуляция / 0
new File(treeUri.toString()).getAbsolutePath();
Возвращает: content: /com.android.externalstorage.documents/tree/primary:
Если вы используете класс DocumentFile для получения пути к главной папке, вы получите
DocumentFile saveDir = null;
saveDir = DocumentFile.fromFile(Environment.getExternalStorageDirectory());
String uriString = saveDir.getUri().toString();
Возвращает: file: /// storage / emulated / 0
Мой первый вопрос: как получить Uri с контентом, используя класс DocumentFile.
Я создаю приложение для фотографии и по умолчанию я хотел бы установить начальную папку для изображений с помощью класса DocumentFile.
@TargetApi(19)
protected DocumentFile getSaveDirMainMemory() {
DocumentFile saveDir = null;
saveDir = DocumentFile.fromFile(Environment.getExternalStorageDirectory());
// saveDir =
// DocumentFile.fromFile(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM));
// saveDir =
// DocumentFile.fromFile(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES));
DocumentFile newDir = null;
/*
* Check or create Main Folder
*/
// Check if main folder exist
newDir = saveDir.findFile(DIR_MAIN);
// Folder does not exist, create it
if (newDir == null || !newDir.exists()) {
newDir = saveDir.createDirectory(DIR_MAIN);
}
/*
* Check or create Sub-Folder
*/
DocumentFile newSubDir = null;
// Check if sub-folder exist
newSubDir = newDir.findFile(DIR_SUB);
// Folder does not exist, create it
if (newSubDir == null || !newSubDir.exists()) {
newSubDir = newDir.createDirectory(DIR_SUB);
}
if (newSubDir != null && newSubDir.exists()) {
return newSubDir;
} else if (newDir != null && newDir.exists()) {
return newDir;
} else {
return saveDir;
}
}
Этот метод создает DIR_MAIN/DIR_SUB в основной памяти устройства или в папке PICTURES или DCIM в зависимости от выбора. Используя эту папку по умолчанию, я сохраняю изображения в эту созданную подпапку. Я получаю newSubDir.getUri(). ToString (): file: /// storage / emulated / 0 / MainFolder / SubFolder. Я назвал DIR_MAIN MainFolder, DIR_SUB: SubFolder для тестирования.
Для доступа или удаления изображений я использую этот путь и имя изображения, которое я создал как
DocumentFile imageToDeletePath = DocumentFile.fromFile(new File(lastSavedImagePath));
DocumentFile imageToDelete = imageToDeletePath.findFile(lastSavedImageName);
imageDelete возвращает ноль, потому что Uri не в правильном формате.
Если я открываю пользовательский интерфейс SAF и получаю UA onActivityResult и сохраняю его как строку, я использую этот метод, чтобы получить каталог и проверить разрешения Uri
@TargetApi(19)
protected DocumentFile getSaveDirNew(String uriString) {
DocumentFile saveDir = null;
boolean canWrite = isUriWritePermission(uriString);
if (canWrite) {
try {
saveDir = DocumentFile.fromTreeUri(MainActivity.this, Uri.parse(uriString));
} catch (Exception e) {
saveDir = null;
}
}
return saveDir;
}
Проверьте, есть ли у Uri из строки разрешение на запись, но может не быть, если вы не берете или не удаляете постоянные разрешения.
private boolean isUriWritePermission(String uriString) {
boolean canWrite = false;
List<UriPermission> perms = getContentResolver().getPersistedUriPermissions();
for (UriPermission p : perms) {
if (p.getUri().toString().equals(uriString) && p.isWritePermission()) {
Toast.makeText(this, "canWrite() can write URI:: " + p.getUri().toString(), Toast.LENGTH_LONG).show();
canWrite = true;
break;
}
}
return canWrite;
}
После сохранения изображения с действующим URI и использования
DocumentFile imageToDeletePath = DocumentFile.fromTreeUri(this, Uri.parse(lastSavedImagePath));
DocumentFile imageToDelete = imageToDeletePath.findFile(lastSavedImageName);
0 ответов
Uri.fromFile()
а также DocumentFile.fromTreeUri()
создать uris из двух разных миров.
Хотя в настоящее время они выглядят очень похоже, это просто совпадение и может измениться в любом будущем выпуске Android.
Нет никакого "нехакерского" способа конвертировать одно в другое. Если вам нужно грязное решение, вы можете пойти на размышление (см. Исходный кодDocumentFile.fromTreeUri
и, возможно, использовать Storage
class в более новых версиях Android.
Также см.: Android - Storage Access Framework - Uri в локальный файл.