gpt4 book ai didi

android - 从 RELATIVE_PATH + DISPLAY_NAME 获取媒体的 URI 或 ID

转载 作者:行者123 更新时间:2023-12-02 12:57:18 25 4
gpt4 key购买 nike

我正在尝试简单地添加音频文件。我的解决方案大多有效。但它不起作用的地方是文件已经存在于 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 条目并相应地更新它。

我尝试使用以下代码在 MediaStore 中查询 ID 但没有成功。找出 IDURI 都可以。此外,从 SDK 29 开始,MediaStore.Audio.Media.DATA 已被弃用。所以我想在不使用它的情况下查询它。

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)

我现在还尝试使用我知道无法插入的硬编码路径查询 _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

也返回 null 并返回 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" id 是 79658 相对路径是 "Music/JDrop/1/1"。前面有一个我不知道的Music/。但是 find12 仍然是空的。

编辑 3(可能重要也可能不重要的其他想法)

可能还值得注意的是,它不会发生在我使用 android 10 创建的 Android 模拟器上。但它会在我的 OnePlus 6 上发生,其中包含大约 300 个文件,并且适用于所有其他文件。我已经在 Android 9 上使用该程序,然后升级到 Android 10。我在某个地方读到,当您升级到 10 时,来自 Android 9 的文件可能被认为是孤立的,而不是属于您的应用程序(至少当您卸载创建它们的应用程序)。所以我可能无法再访问我正在寻找的媒体存储条目?不过,我也想过。现在,任何应用程序都可以在未经任何许可的情况下访问阅读媒体。因此,如果这是一个访问问题,则在尝试写入时应该会失败。不是在阅读或找到它时。

此外,正如@CommonsWare 提到的,IS_PENDING 仍可能设置为 1。我确实在我发布的代码下方将其设置回 0。但是,每当我在调试时关闭程序时,该代码可能永远不会执行,因为它会在下载和写入文件的部分执行 9/10 次,因为这花费了到目前为止最长的时间程序中发生的任何事情。

最佳答案

我现在想通了这个问题。感谢@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" }
}

现在我可以开始让它再次正常工作了。


编辑Android11

出现在 Android11 上的 MediaStore.setIncludePending(collection) 现已弃用,我们应该改为 use a different query method that accepts a bundle .

所以就变成了这个样子

val queryCollection =
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.R)
MediaStore.setIncludePending(collection)
else collection

val queryProjection = arrayOf(MediaStore.Audio.Media._ID)

val querySelection = "${MediaStore.Audio.Media.RELATIVE_PATH}=? AND ${MediaStore.Audio.Media.DISPLAY_NAME}=?"
val querySelectionArgs = arrayOf("someRelativePath", "someFilename")

val queryBundle = Bundle().apply {
putString(ContentResolver.QUERY_ARG_SQL_SELECTION, querySelection)
putStringArray(ContentResolver.QUERY_ARG_SQL_SELECTION_ARGS, querySelectionArgs)
}

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
queryBundle.putInt(MediaStore.QUERY_ARG_MATCH_PENDING, MediaStore.MATCH_INCLUDE)

ctx.contentResolver.query(queryCollection, queryProjection, queryBundle, null)?.use {
... Do something
}

在 android 11 之前,那些用于在 bundle 中包含待定项目的变量不可用。

为 android 10 支持启用传统存储并像 android < 10 一样使用它并且只在 android 10 上实现范围存储可能是一个更好的主意。该选项在 android 11 上被忽略,但如果应用程序运行仍然有效在安卓 10 上。

关于android - 从 RELATIVE_PATH + DISPLAY_NAME 获取媒体的 URI 或 ID,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59904243/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com