Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

The following code is used to save files from the app to downloads:

    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");

Everything is saved, however, if you delete the file from downloads manually, and then try to download it again from the application, an error appears:

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

Is there a way to fix this or will I have to use unique names for each download?

This error happens because the machanism of OS: if we delete manually a file (media), its database will not be deleted immediately. Until we restart device.

Have a approach for this problem (still not be optimized - hope receiving sharing from people), such as:

Step 1: Get info of file via its name

Step 2: Ask OS to update its database via MediaScannerConnection.scanFile

Step 3: Use current code that has above problem

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 {
    // Save file normally
    // Use current code have this problem
        

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.