使用安卓媒体存储时,代码2067 SQLITE_CONSTRAINT_UNIQUE

1 人关注

下面的代码用于将文件从应用程序保存到下载。

    Uri collection = MediaStore.Downloads.EXTERNAL_CONTENT_URI;
    ContentValues values = new ContentValues();
    values.put(MediaStore.Downloads.DISPLAY_NAME, filename);
    values.put(MediaStore.Downloads.MIME_TYPE, mimeType);
    values.put(MediaStore.Downloads.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS);
    ContentResolver contentResolver = context.getApplicationContext().getContentResolver();
    Uri uri = contentResolver.insert(collection, values);
    OutputStream outputStream = context.getApplicationContext().getContentResolver().openOutputStream(uri, "w");

一切都被保存了,然而,如果你从下载中手动删除文件,然后试图从应用程序中再次下载,就会出现错误。

android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: files._data (code 2067 SQLITE_CONSTRAINT_UNIQUE[2067])

是否有办法解决这个问题,或者我必须为每个下载使用独特的名称?

android
android-studio
Kensamare
Kensamare
发布于 2022-02-06
1 个回答
phvlchm
phvlchm
发布于 2022-11-23
0 人赞同

这个错误的发生是因为操作系统的机制:如果我们手动删除一个文件(媒体),它的数据库不会被立即删除。直到我们重新启动设备。

对这个问题有一个办法(还没有优化--希望收到大家的分享),比如说。

第1步:通过文件名获取文件的信息

第二步:要求操作系统通过 MediaScannerConnection.scanFile 更新其数据库。

第3步:使用存在上述问题的当前代码

Codes for steps (collected on internet)

Step 1:

fun findByFileName(fileName: String): MutableList<FileInfo> {
    val files = mutableListOf<FileInfo>()
    val collection =
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL)
        } else {
            MediaStore.Video.Media.EXTERNAL_CONTENT_URI
    val projection = arrayOf(
        MediaStore.Video.Media._ID,
        MediaStore.Video.Media.DISPLAY_NAME,
        MediaStore.Video.Media.DURATION,
        MediaStore.Video.Media.SIZE,
        MediaStore.Video.Media.DATA
    val selection = "${MediaStore.Video.Media.DISPLAY_NAME} LIKE ?"
    val selectionArgs = arrayOf(
        fileName
    // Display videos in alphabetical order based on their display name.
    val sortOrder = "${MediaStore.Video.Media.DISPLAY_NAME} ASC"
    val query = context.contentResolver.query(
        collection,
        projection,
        selection,
        selectionArgs,
        sortOrder
    query?.use { cursor ->
        // Cache column indices.
        val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID)
        val nameColumn =
            cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME)
        val durationColumn =
            cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION)
        val sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE)
        val dataColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA)
        while (cursor.moveToNext()) {
            // Get values of columns for a given video.
            val id = cursor.getLong(idColumn)
            val name = cursor.getString(nameColumn)
            val duration = cursor.getInt(durationColumn)
            val size = cursor.getInt(sizeColumn)
            val data = cursor.getStringOrNull(dataColumn)
            val contentUri: Uri = ContentUris.withAppendedId(
                MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
            // Stores column values and the contentUri in a local object
            // that represents the media file.
            files += FileInfo(contentUri, name, duration, size, data)
    return files
data class FileInfo(
    val uri: Uri,
    val name: String,
    val duration: Int,
    val size: Int,
    val data: String? = null

Step 2 + Step 3:

val exitedData = findByFileName(fileName = name)
if (exitedData != null) {
    MediaScannerConnection.scanFile(context, arrayOf(exitedData.first().data.toString()), null, object: MediaScannerConnection.OnScanCompletedListener {
        override fun onScanCompleted(path: String?, uri: Uri?) {
            // Step 3
            // Use current code have this problem
} else {