Получите URI или ID для медиа от RELATIVE_PATH + DISPLAY_NAME - PullRequest
2 голосов
/ 25 января 2020

Я пытаюсь просто добавить аудио файлы. Мое решение в основном работает. Но он не работает, когда файл уже существует в MediaStore. Как только я посмотрел более внимательно, также только существует в MediaStore, в этом месте на устройстве нет файла.

val values = ContentValues().apply {
   put(MediaStore.Audio.Media.RELATIVE_PATH, libraryPart.rootFolderRelativePath) // JDrop/1/1
   put(MediaStore.Audio.Media.DISPLAY_NAME, remoteLibraryEntry.getFilename()) //12.mp3
   put(MediaStore.Audio.Media.IS_PENDING, 1)
   if(mimeType != null)
       put(MediaStore.Audio.Media.MIME_TYPE, mimeType) // audio/mpeg3
}

val collection = MediaStore.Audio.Media
       .getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)

var uri = ctx.contentResolver.insert(collection, values) // returns null for around 300/2000 files consistently

Logcat выдает следующее при попытке вставьте этот новый файл.

2020-01-24 22:27:33.724 4015-7707/? E/SQLiteDatabase: Error inserting title_key= bucket_display_name=1 owner_package_name=shio.at.jdrop parent=79657 volume_name=external_primary title_resource_uri=null _display_name=12.mp3 mime_type=audio/mpeg3 _data=/storage/emulated/0/Music/JDrop/1/1/12.mp3 title= group_id=1569 artist_id=322 is_pending=1 date_added=1579901253 album_id=2958 primary_directory=Music secondary_directory=JDrop bucket_id=687581593 media_type=2 relative_path=Music/JDrop/1/1/ from {P:30220;U:10165}
android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: files._data (code 2067 SQLITE_CONSTRAINT_UNIQUE)
    at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method)
    at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:879)
    at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:790)
    at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:88)
    at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1639)
    at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1494)
    at com.android.providers.media.MediaProvider.insertFile(MediaProvider.java:3050)
    at com.android.providers.media.MediaProvider.insertInternal(MediaProvider.java:3452)
    at com.android.providers.media.MediaProvider.insert(MediaProvider.java:3240)
    at android.content.ContentProvider$Transport.insert(ContentProvider.java:325)
    at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:164)
    at android.os.Binder.execTransactInternal(Binder.java:1032)
    at android.os.Binder.execTransact(Binder.java:1005)

Так что files._data будет означать, что файл уже существует в MediaStore. В JDrop/1/1/12.mp3 нет файла, он находится только в MediaStore, и мне нужно как-то избавиться от него или получить OutputStream для существующей записи MediaStore и соответственно обновить его.

У меня есть попытался запросить ID в MediaStore безуспешно, используя следующий код. Либо выяснить, ID или URI было бы хорошо. Более того, MediaStore.Audio.Media.DATA устарело с SDK 29. Поэтому я хотел бы запросить его, не используя это.

if(uri == null) {
    val id: Long = ctx.contentResolver.query(
            collection,
            arrayOf(BaseColumns._ID),
            "${MediaStore.Audio.Media.RELATIVE_PATH}=? AND ${MediaStore.Audio.Media.DISPLAY_NAME}=?",
            arrayOf(libraryPart.rootFolderRelativePath, remoteLibraryEntry.getFilename()),
            null)?.use {
        if (it.moveToNext())
            it.getLong(it.getColumnIndex(BaseColumns._ID))
        else null
    } ?: return false

    uri = Uri.withAppendedPath(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id!!.toString())
}

РЕДАКТИРОВАТЬ 1 (запрос _данных)

Я также сейчас пытался выполнить запрос к _data с жестко закодированным путем, который, как я знаю, я не могу вставить, без особого успеха.

val id: Long = ctx.contentResolver.query(
            collection,
            arrayOf(BaseColumns._ID),
            "${MediaStore.Audio.Media.DATA}=?",
            arrayOf("/storage/emulated/0/Music/JDrop/1/1/12.mp3"),
            null)?.use {
        if (it.moveToNext())
            it.getLong(it.getColumnIndex(BaseColumns._ID))
        else null
    } ?: return false

Также возвращает ноль и возвращает ложь.

РЕДАКТИРОВАТЬ 2 (Запрашивать все и посмотреть, что это возвращает)

Я попытался выполнить небольшой тестовый запрос к более полной коллекции, как было предложено.

class TestQueryObject(val id: Long, val relativePath: String, val displayName: String)
val results = mutableListOf<TestQueryObject>()

ctx.contentResolver.query(
        collection,
        arrayOf(MediaStore.Audio.Media._ID, MediaStore.Audio.Media.RELATIVE_PATH, MediaStore.Audio.Media.DISPLAY_NAME),
        null,
        null,
        null)?.use {
    while (it.moveToNext()) {
        results.add(TestQueryObject(
                id = it.getLong(it.getColumnIndex(MediaStore.Audio.Media._ID)),
                relativePath = it.getString(it.getColumnIndex(MediaStore.Audio.Media.RELATIVE_PATH)),
                displayName = it.getString(it.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME))
        ))
    }
}

var find12 = results.find { it.displayName == "12.mp3" }

Возвращает список из 2557 записей. В качестве примера для первого имя "5.mp3", идентификатор 79658, относительный путь "Music/JDrop/1/1". Перед ним Music/, о котором я не знал. Но find12 по-прежнему нулевой.

РЕДАКТИРОВАТЬ 3 (Дополнительные мысли, которые могут или не могут быть важными)

Возможно, также стоит отметить, что это не происходит на эмуляторе Android, который я созданный с android 10. Но он работает на моем OnePlus 6 примерно с этими 300'i sh файлами и работает для всех остальных. Я уже использовал Программу с Android 9, а затем обновил до Android 10. Я где-то читал, что файлы с Android 9 при обновлении до 10 могут считаться осиротевшими, а не принадлежать к вашей заявке (в по крайней мере, это то, что происходит при удалении приложения, которое их создало). Так что я могу просто больше не иметь доступа к нужным записям медиасторма? Впрочем, я тоже подумал. носители для чтения теперь доступны для любого приложения без ЛЮБОГО разрешения. Так что, если это проблема с доступом, она может потерпеть неудачу при попытке записи в нее. Не при чтении или поиске.

Кроме того, как упоминалось @CommonsWare, IS_PENDING все еще может быть установлено на 1. Я вернул значение 0 в коде ниже того, что я написал. Тем не менее, этот код может никогда не выполняться, когда я закрываю программу во время отладки, поскольку 9/10 раз он будет в той части, где он загружает и записывает файл, так как это занимает намного самое длинное время из всех происходит в программе.

1 Ответ

0 голосов
/ 25 января 2020

Я выяснил проблему сейчас. Спасибо @CommonsWare, чтобы упомянуть ожидающий бит. Мне, возможно, потребовалось намного больше , чтобы понять это.

Существует метод Uri MediaStore.setIncludePending(Uri uri), в который вы передаете свой URI, и вы получаете URI с ведьмой, которую вы можете запросить с помощью ожидающие элементы включены.

Использование этого нового Uri, полученного с помощью этого метода, возвращает мою find12 вещь успешно!

val collection = MediaStore.Audio.Media
    .getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)

var uri = ctx.contentResolver.insert(collection, values)

if(uri == null) {

    class TestQueryObject(val id: Long, val relativePath: String, val displayName: String)
    val results = mutableListOf<TestQueryObject>()

    ctx.contentResolver.query(
            MediaStore.setIncludePending(collection),
            arrayOf(MediaStore.Audio.Media._ID, MediaStore.Audio.Media.RELATIVE_PATH, MediaStore.Audio.Media.DISPLAY_NAME),
            null,
            null,
            null)?.use {
        while (it.moveToNext()) {
            results.add(TestQueryObject(
                    id = it.getLong(it.getColumnIndex(MediaStore.Audio.Media._ID)),
                    relativePath = it.getString(it.getColumnIndex(MediaStore.Audio.Media.RELATIVE_PATH)),
                    displayName = it.getString(it.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME))
            ))
        }
    }

    var find12 = results.find { it.displayName == "12.mp3" }
}

Теперь я могу начать заставлять это фактически работать снова.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...