Как получить DocumentContract с помощью Android Storage Access Framework

Я пытаюсь реализовать SAF в своем приложении. Мне удалось скопировать музыкальные файлы на внешнюю SD-карту, используя следующее:

         Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
    startActivityForResult(intent, REQUEST_CODE_OPEN_DIRECTORY);

который вызывает Средство выбора файлов / папок

копировать:

   private String copyFile(String inputPath, String inputFile, Uri treeUri) {
    InputStream in = null;
    OutputStream out = null;
    String error = null;
    DocumentFile pickedDir = DocumentFile.fromTreeUri(getActivity(), treeUri);
    String extension = inputFile.substring(inputFile.lastIndexOf(".")+1,inputFile.length());

    try {
        DocumentFile newFile = pickedDir.createFile("audio/"+extension, inputFile);
        out = getActivity().getContentResolver().openOutputStream(newFile.getUri());
        in = new FileInputStream(inputPath + inputFile);

        byte[] buffer = new byte[1024];
        int read;
        while ((read = in.read(buffer)) != -1) {
            out.write(buffer, 0, read);
        }
        in.close();
        // write the output file (You have now copied the file)
        out.flush();
        out.close();

    } catch (FileNotFoundException fnfe1) {
        error = fnfe1.getMessage();
    } catch (Exception e) {
        error = e.getMessage();
    }
    return error;
}

НО, когда пользователь выбрал «переместить», я хочу удалить файлы в исходном месте (ах), которые могут не находиться в дереве документов, поскольку они не имеют ничего общего с выбранной папкой. Их пути берутся из поля Mediastore_DATA. Вопрос в том, как мне получить DocumentContract с этими файлами, чтобы я мог их удалить?


person Theo    schedule 28.03.2017    source источник
comment
Зачем вам нужен договор с документами? Вы просто можете использовать класс File для их удаления, так как у вас есть полный путь, который вы использовали для FileInputStream.   -  person greenapps    schedule 29.03.2017
comment
which brings up the File/folder Picker. Нет. Тогда вы сможете только выбрать папку. Дерево. Нет файла.   -  person greenapps    schedule 29.03.2017
comment
Their paths are taken from the Mediastore_DATA field.. Почему?. Вы только показали, как выбрать целевой каталог. Но вы не сказали, как пользователь выбрал музыкальные файлы, которые нужно было скопировать / переместить. Я думаю, тебе тоже стоит это сказать.   -  person greenapps    schedule 29.03.2017
comment
@greenaps необходим контракт, так как удаление может происходить на внешней SD-карте. Меня интересует только копирование в папку. Музыкальные файлы являются записями в списке воспроизведения и, таким образом, могут храниться во внутренней или внешней памяти. Вся идея состоит в том, чтобы скопировать или переместить треки из списка воспроизведения в новую папку, а в случае перемещения впоследствии удалить оригиналы.   -  person Theo    schedule 29.03.2017
comment
Вы не ответили на мой Why?. Или дал дополнительную информацию, необходимую для решения вашей проблемы.   -  person greenapps    schedule 29.03.2017
comment
чтобы ответить на ваш вопрос, почему, вы не можете удалить на внешней SD-карте с api19 или выше без использования Storage Access Framework   -  person Theo    schedule 29.03.2017
comment
Конечно, это вообще не ответ. Пожалуйста, перечитайте. Перед этим стоит вопрос: «Почему?».   -  person greenapps    schedule 29.03.2017
comment
Спасибо, greenapps, но я не думаю, что мы чего-то добиваемся. Спасибо за ответ   -  person Theo    schedule 29.03.2017
comment
Не думай! Ни к чему не приводит. Отвечать! ;-).   -  person greenapps    schedule 29.03.2017


Ответы (1)


Невозможно получить разрешение URI от SAF без вызова другого пользовательского интерфейса.

Поскольку вы используете MediaStore для получения мультимедийного файла, вы можете использовать ContentResolver.delete () с URI мультимедиа, который необходимо удалить. Я предполагаю, что у вас есть разрешение WRITE_EXTERNAL_STORAGE. Я не рекомендую использовать File для непосредственного удаления базового файла, поскольку у MediaStore не будет возможности его очистить.

Кроме того, вы также можете попробовать https://developer.android.com/reference/android/os/storage/StorageVolume.html#createAccessIntent(java.lang.String), чтобы получить разрешение URI дерева для всего основного хранилища. Однако он работает только с API 24.

person ttanxu    schedule 07.04.2017
comment
ttanxu, спасибо, что ответили на мой вопрос. Я пытался удалить с помощью нового файла (fullpath_from_Mediastore_DATA) .delete (); метод, но на внешней SD-карте ничего не удаляется. Я надеялся получить дерево документа (одноразовое намерение с использованием ACTION_OPEN_DOCUMENT_TREE, записывая результат в настройках), а затем добавить каждую дорожку в documentTree uri. при перечислении дочерних элементов дерева. Я использую приложение LocalStorage из Github в качестве примера - person Theo; 07.04.2017
comment
Ссылка, которую вы предоставили, выглядит многообещающей - person Theo; 07.04.2017
comment
Вы уже получили _data столбец из MediaStore, вы должны иметь возможность вызвать mContext.getContentResolver().delete(MediaStore.Files.getContentUri("external"), "lower(_data) = lower(?)", new String[] { path_from_MediaStore_DATA }); для удаления элемента как из MediaStore, так и с диска, если вы удерживаете WRITE_EXTERNAL_STORAGE_PERMISSION. - person ttanxu; 10.04.2017
comment
приведенное выше приведет к удалению только записи трека из Mediastore. Он не удалит сам файл. WRITE_EXTERNAL и т.д. есть в манифесте, но все дело в том, что file.delete не будет работать, поэтому я вернулся к квадрату 1. Я думаю, что именно поэтому Google придумал StorageVolume. Их подход к внедрению системы безопасности мне кажется несколько случайным. Спасибо за помощь. Я проверю подход StorageVolume. - person Theo; 17.04.2017