Правильно удалите DocumentFile (соблюдая MediaStore)
У меня есть DocumentFile
определяется следующими двумя способами:
DocumentFile documentFile;
Uri documentFileUri;
Я могу удалить файл документа с SD-карты следующими способами:
documentFile.delete();
DocumentsContract.deleteDocument(contentResolver, documentFileUri);
Но ни один из вышеперечисленных методов не удалит соответствующую запись из MediaStore
,
Какой правильный способ справиться с этим? Если я использую ContentProvider
для удаления локального файла, он удалит File
И строка из базы данных (contentResolver.delete(localFileUri, null, null);
). Я ожидаю, что то же самое произойдет, если я использую DocumentsContract
но этого не происходит...
Что я хочу
Я хочу по-настоящему обновить MediaStore
, Обычно я бы позвонил contentResolver.delete(documentFileUri, null, null);
но это не удастся, за исключением того, что URI не поддерживает удаления...
Вопрос
Есть ли более эффективный способ сделать это, чем мой обходной путь?
Временное решение
В настоящее время я использую следующую функцию для мгновенного обновления хранилища мультимедиа после удаления DocumentFile
:
public static boolean updateAfterChangeBlocking(String path, int timeToWaitToRecheckMediaScanner)
{
final AtomicBoolean changed = new AtomicBoolean(false);
MediaScannerConnection.scanFile(StorageManager.get().getContext(),
new String[]{path}, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
changed.set(true);
}
});
while (!changed.get()) {
try {
Thread.sleep(timeToWaitToRecheckMediaScanner);
} catch (InterruptedException e) {
return false;
}
}
return true;
}
1 ответ
Как отметил Толстяк, поведение является заданным - задокументировано в этой проблеме Google: https://issuetracker.google.com/issues/138887165
Решение:
Вероятно, нет лучшего решения, чем то, что я уже написал в своем вопросе, чем следующее:
- удалить файл через
DocumentFile
объект или этоURI
а такжеDocumentsContract.deleteDocument
- для мгновенного обновления медиа-магазина (это то, что я хотел), вы должны вручную обновить медиа-магазин, например, позвонив
MediaScannerConnection.scanFile(...)
как я уже разместил в своем вопросе
Я немного опоздал, но я надеюсь, что приду с решением проблемы... даже спустя 2 года с момента публикации этого вопроса. Полный пример кода можно найти здесь https://drive.google.com/file/d/1zCdaGwslr5XfWH_t0iZPKDukChOLXMg3/view?usp=sharing. (написано на Kotlin) Этот код работал для меня для версии Android LOLLIPOP и выше.
Код прост и его легко понять.
Этот менеджер файлов с открытым исходным кодом имеет функцию удаления файлов, которая вам нужна
static boolean deleteFile(@NonNull final File file, Context context) {
// First try the normal deletion.
if (file == null) return true;
boolean fileDelete = rmdir(file, context);
if (file.delete() || fileDelete)
return true;
// Try with Storage Access Framework.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && FileUtil.isOnExtSdCard(file, context)) {
DocumentFile document = getDocumentFile(file, false, context);
return document.delete();
}
// Try the Kitkat workaround.
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
ContentResolver resolver = context.getContentResolver();
try {
Uri uri = MediaStoreHack.getUriFromFile(file.getAbsolutePath(), context);
resolver.delete(uri, null, null);
return !file.exists();
} catch (Exception e) {
Log.e(LOG, "Error when deleting file " + file.getAbsolutePath(), e);
return false;
}
}
return !file.exists();
}