簡體   English   中英

MediaStore contentResolver.insert() 在拍照時創建副本而不是替換現有文件(Android Q:29)

[英]MediaStore contentResolver.insert() creates copies instead of replacing the existing file when taking photos (Android Q: 29)

我正在嘗試使用以下代碼保存從相機拍攝的圖像:

@RequiresApi(Build.VERSION_CODES.Q)
private fun setImageUri(): Uri {
    val resolver = contentResolver
    val contentValues = ContentValues().apply {
        put(MediaStore.MediaColumns.DISPLAY_NAME, "house2.jpg")
        put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
        put(MediaStore.MediaColumns.RELATIVE_PATH, "Pictures/OLArt")
    }

    imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)

    return imageUri!!
}

該功能第一次運行良好。 然而,當圖像(house2.jpg)已經存在時,系統將創建另一個名為“house2 (1).jpg”、“house2 (2).jpg”等的文件(而不是替換舊文件)

在此處輸入圖片說明

我可以在 contentValues 中設置什么來強制解析器替換文件而不是創建它的副本嗎?

下面是拍照意圖的代碼。

 Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->

     takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, setImageUri()) //<- i paste in the imageUri here

     // Ensure that there's a camera activity to handle the intent
     takePictureIntent.resolveActivity(packageManager)?.also {

         startActivityForResult(takePictureIntent, 102)
     }
  }

@CommonsWare 的評論有幫助。

這個想法是

  1. 使用 resolver.query() 查詢文件是否已存在
  2. 如果是,則從光標中提取 contentUri
  3. 否則,使用 resolver.insert()

創建查詢選擇時要注意的一件事是 MediaStore.MediaColumns.RELATIVE_PATH 需要終止“/”

即 'Pictures/OLArt/' << 注意 OLArt/ 后的斜線

    val selection = "${MediaStore.MediaColumns.RELATIVE_PATH}='Pictures/OLArt/' AND " 
                   + "${MediaStore.MediaColumns.DISPLAY_NAME}='house2.jpg' "

以下是更新后的代碼。

@RequiresApi(Build.VERSION_CODES.Q)
private fun getExistingImageUriOrNullQ(): Uri? {
    val projection = arrayOf(
        MediaStore.MediaColumns._ID,
        MediaStore.MediaColumns.DISPLAY_NAME,   // unused (for verification use only)
        MediaStore.MediaColumns.RELATIVE_PATH,  // unused (for verification use only)
        MediaStore.MediaColumns.DATE_MODIFIED   //used to set signature for Glide
    )

    // take note of the / after OLArt
    val selection = "${MediaStore.MediaColumns.RELATIVE_PATH}='Pictures/OLArt/' AND " 
                  + "${MediaStore.MediaColumns.DISPLAY_NAME}='house2.jpg' "

    contentResolver.query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
        projection, selection, null, null ).use { c ->
        if (c != null && c.count >= 1) {

            print("has cursor result")
            c.moveToFirst().let {

                val id = c.getLong(c.getColumnIndexOrThrow(MediaStore.MediaColumns._ID) )
                val displayName = c.getString(c.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME) )
                val relativePath = c.getString(c.getColumnIndexOrThrow(MediaStore.MediaColumns.RELATIVE_PATH) )
                lastModifiedDate = c.getLong(c.getColumnIndexOrThrow(MediaStore.MediaColumns.DATE_MODIFIED) )

                imageUri = ContentUris.withAppendedId(   
                             MediaStore.Images.Media.EXTERNAL_CONTENT_URI,  id)

                print("image uri update $displayName $relativePath $imageUri ($lastModifiedDate)")

                return imageUri
            }
        }
    }
    print("image not created yet")
    return null
}

然后我將此方法添加到我現有的代碼中

@RequiresApi(Build.VERSION_CODES.Q)
private fun setImageUriQ(): Uri {

    val resolver = contentResolver

    imageUri = getExistingImageUriOrNullQ() //try to retrieve existing uri (if any)
    if (imageUri == null) {

       //=========================
       // existing codes for resolver.insert
       //(SNIPPED)
       //=========================
    }
    return imageUri!!
}

Angel Koh 的回答是正確的。

我只是用Java發布它:

@RequiresApi(Build.VERSION_CODES.Q)
public static Uri CheckIfUriExistOnPublicDirectory(Context c ,String[] projection, String selection){

    ContentResolver resolver = c.getContentResolver();
    Cursor cur = resolver.query(MediaStore.Downloads.EXTERNAL_CONTENT_URI, projection, selection , null, null);

    if (cur != null) {

        if(cur.getCount()>0){

            if (cur.moveToFirst()) {
                String filePath = cur.getString(0);
                long id = cur.getLong(cur.getColumnIndexOrThrow(MediaStore.MediaColumns._ID));
                String displayName = cur.getString(cur.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME) );
                String relativePath = cur.getString(cur.getColumnIndexOrThrow(MediaStore.MediaColumns.RELATIVE_PATH) );
                long z = cur.getLong(cur.getColumnIndexOrThrow(MediaStore.MediaColumns.DATE_MODIFIED) );

                return imageUri = ContentUris.withAppendedId(
                        MediaStore.Images.Media.EXTERNAL_CONTENT_URI,  id);

            } else {
                // Uri was ok but no entry found.
            }

        }else{
            // content Uri was invalid or some other error occurred
        }
        cur.close();
    } else {
        // content Uri was invalid or some other error occurred
    }

    return null;
}

和使用方法:

String[] projection = {MediaStore.MediaColumns._ID,
                MediaStore.MediaColumns.DISPLAY_NAME,
                MediaStore.MediaColumns.RELATIVE_PATH,
                MediaStore.MediaColumns.DATE_MODIFIED
        };

        String selection = MediaStore.MediaColumns.RELATIVE_PATH + "='" + Environment.DIRECTORY_DOWNLOADS + File.separator + folderName + File.separator + "' AND "
                + MediaStore.MediaColumns.DISPLAY_NAME+"='" + fileName + "'";

        uri = CheckIfUriExistOnPublicDirectory(context,projection,selection);
        if(uri != null){
            // file already exist
        }else{
            // file not exist, insert
        }

這是正確的預期行為。 您看到不同的編號后綴的原因,可能是因為您將文件保存在同一文件夾中,因此 Android 必須創建一個唯一的名稱,以允許文件存在於同一位置。

Insert方法旨在始終創建新記錄。 它返回的 Uri 始終是新插入的記錄。 但是如果文件保存在已經有另一個同名文件的文件夾中,那么這樣的文件名必須不同,Android 將附加數值。

如果您希望替換現有記錄,那么您必須首先找到它的 Uri,然后通過調用 ContentResolver 更新方法來使用它。

如果您從相機應用程序保存照片,那么您可以使用當前時間作為名稱,包括毫秒,以確保唯一。

您是否嘗試過使用方法 update

檢查它是否在沒有任何內容時創建一個新文件,如果它不起作用,則根據文件是否已創建使用插入或更新。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM