Я пытаюсь просто добавить аудио файлы. Мое решение в основном работает. Но он не работает, когда файл уже существует в 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 раз он будет в той части, где он загружает и записывает файл, так как это занимает намного самое длинное время из всех происходит в программе.