【问题标题】:`MediaStore.MediaColumns.DATA` is deprecated, what column should I use as an alternative`MediaStore.MediaColumns.DATA` 已弃用,我应该使用什么列作为替代
【发布时间】:2022-03-14 14:18:00
【问题描述】:

我想使用MediaStore API 将媒体提供程序中的所有图片加载到我的应用程序中,但此列MediaStore.MediaColumns.DATA 已弃用。那么,我可以用什么来替代呢?

我想更新以下代码以摆脱已弃用的MediaStore.MediaColumns.DATA 列:

fun ContentResolver.loadImagesPaths(): List<String> {
    val uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
    val images = mutableListOf<String>()
    val projection = arrayOf(MediaStore.MediaColumns.DATA)
    query(uri, projection, null, null, null)?.use { cursor ->
        val dataColumn = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA)
        while (cursor.moveToNext()) {
            images += cursor.getString(dataColumn)
        }
    }
    return images
}

编辑:

更新代码:

fun ContentResolver.loadImagesUris(): List<Uri> {
    val uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
    val images = mutableListOf<Uri>()
    val projection = arrayOf(MediaStore.Images.Media._ID)
    query(uri, projection, null, null, null)?.use { cursor ->
        val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
        while (cursor.moveToNext()) {
            images += ContentUris.withAppendedId(uri, cursor.getLong(idColumn))
        }
    }
    return images
}

查看此链接以获取有关如何从共享存储访问媒体文件的更多详细信息:https://developer.android.com/training/data-storage/shared/media

【问题讨论】:

标签: java android kotlin


【解决方案1】:

我能够将 MediaStore.MediaColumns.Data 替换为它自己的文件 ID(令人难以置信的是,文件有 ID)并正确地构造了它的 URI,如下所示:

fun getAllShownImagesPath(activity: Activity): MutableList<Uri> {
    val uriExternal: Uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
    val cursor: Cursor?
    val columnIndexID: Int
    val listOfAllImages: MutableList<Uri> = mutableListOf()
    val projection = arrayOf(MediaStore.Images.Media._ID)
    var imageId: Long
    cursor = activity.contentResolver.query(uriExternal, projection, null, null, null)
    if (cursor != null) {
        columnIndexID = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
        while (cursor.moveToNext()) {
            imageId = cursor.getLong(columnIndexID)
            val uriImage = Uri.withAppendedPath(uriExternal, "" + imageId)
            listOfAllImages.add(uriImage)
        }
        cursor.close()
    }
    return listOfAllImages
}

然后使用 Uri 在视图中构建它!

【讨论】:

  • 你也可以使用“cursor.getString()”,我没有测试它,但它可能看起来比“cursor.getLont()”更好
【解决方案2】:

我设法想出了以下解决方案,它是对之前answer 的补充

但是我仍然无法使用获得的 Uri 加载图像。 Documentation 建议使用我所做的 openFileDescriptor() 然后从中解码图像的位图:

override fun loadImagesFromStorage(): List<AdapterImage> {

    val uri: Uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
    val cursor: Cursor?
    val columnIndexId: Int
    val listOfAllImages = mutableListOf<AdapterImage>()
    val projection = arrayOf(MediaStore.Images.Media._ID)
    cursor = context.contentResolver
        .query( uri, projection, null, null, null)

    if ( cursor != null ){
        columnIndexId = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
        while (cursor.moveToNext()){

            val contentUri = ContentUris.withAppendedId(uri, cursor.getLong(columnIndexId))

            //here I open FileDescriptor and then decode it into Bitmap
            var image: Bitmap
            context.contentResolver.openFileDescriptor(contentUri, "r").use { pfd ->
                if( pfd != null ){
                    image = BitmapFactory.decodeFileDescriptor(pfd.fileDescriptor)
                    listOfAllImages.add(AdapterImage(image))
                }
            }

        }
        cursor.close()
    }

    return listOfAllImages
}

附:我的方法将返回我稍后在应用程序中使用的 AdapterImage 对象的列表,但此时您可以将所需的任何内容放在那里

【讨论】:

  • 以前,我使用文件路径加载所有带有Glide 的图像。如何将 Glide 与 openFileDescriptor 一起使用?像你一样,我无法让事情只使用Uri
  • @user246392 我来晚了,但您可以简单地使用生成的 contentUri,就像上面的答案中的 Glide 一样。 val contentUri = ContentUris.withAppendedId(uri, cursor.getLong(columnIndexId))
【解决方案3】:

我终于通过创建这个类解决了这个问题

class FileHelper {
val mediaType = "multipart/form-data".toMediaTypeOrNull()

fun getPartBodyFromUri(context: Context, uri: Uri): MultipartBody.Part {
    val realPath = getPathFromURI(context, uri)
    val fileImage = createFile(realPath)
    val requestBody = createRequestBody(fileImage)
    return createPart(fileImage, requestBody)
}

private fun createFile(realPath: String): File {
    return File(realPath)
}

private fun createRequestBody(file: File): RequestBody {
    return file.asRequestBody(mediaType)
}

private fun createPart(file: File, requestBody: RequestBody): MultipartBody.Part {
    return MultipartBody.Part.createFormData("imageFile", file.name, requestBody)
}

private fun getPathFromURI(context: Context, uri: Uri): String {
    var realPath = String()
    uri.path?.let { path ->

        val databaseUri: Uri
        val selection: String?
        val selectionArgs: Array<String>?
        if (path.contains("/document/image:")) { // files selected from "Documents"
            databaseUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
            selection = "_id=?"
            selectionArgs = arrayOf(DocumentsContract.getDocumentId(uri).split(":")[1])
        } else { // files selected from all other sources, especially on Samsung devices
            databaseUri = uri
            selection = null
            selectionArgs = null
        }
        try {
            val column = "_data"
            val projection = arrayOf(column)
            val cursor = context.contentResolver.query(
                databaseUri,
                projection,
                selection,
                selectionArgs,
                null
            )
            cursor?.let {
                if (it.moveToFirst()) {
                    val columnIndex = cursor.getColumnIndexOrThrow(column)
                    realPath = cursor.getString(columnIndex)
                }
                cursor.close()
            }
        } catch (e: Exception) {
            println(e)
        }
    }
    return realPath
}

}

Media.DATA 已弃用,“MediaStore.Images.Media._ID”无法获取正确的列,因此我创建了我需要的列

val column = "_data"
val projection = arrayOf(column)

然后我使用 getColumnIndexOrThrow() 方法来获取正确的索引

val columnIndex = cursor.getColumnIndexOrThrow(column)
realPath = cursor.getString(columnIndex)

【讨论】:

  • cursor.moveToFirst() 当 path.contains("/document/image:") 为真时仍然返回假。
【解决方案4】:

在 Java 中

FileInputStream input = null;
    FileOutputStream output = null;
    try {
        String filePath = new File(getCacheDir(), "tmp").getAbsolutePath();
        android.os.ParcelFileDescriptor pfd = getContentResolver ().openFileDescriptor(
            sharedFileUri, "r");
        if (pfd != null) {
            FileDescriptor fd = pfd . getFileDescriptor ();
            input = new FileInputStream (fd);
            output = new FileOutputStream (filePath);
            int read;
            byte[] bytes = new byte[4096];
            while ((read = input.read(bytes)) != -1) {
                output.write(bytes, 0, read);
            }
            File sharedFile = new File(filePath);
            String finalPath = sharedFile.getPath();
        }
    }catch(Exception ex) {
    } finally {
        try {
            input.close();
            output.close();
        } catch (Exception ignored) {
        }
    }

【讨论】:

    【解决方案5】:

    从内部存储加载图像。使用 MediaStore 类读取所有包含图像和视频的文件夹。

    并将结果返回为 ArrayList。

    private fun getAllShownImagesPath(activity: Activity): ArrayList<Albums> {
    
    val uri: Uri
    val cursor: Cursor
    var cursorBucket: Cursor
    val column_index_data: Int
    val column_index_folder_name: Int
    val listOfAllImages = ArrayList<String>()
    var absolutePathOfImage: String? = null
    var albumsList = ArrayList<Albums>()
    var album: Albums? = null
    
    
    val BUCKET_GROUP_BY = "1) GROUP BY 1,(2"
    val BUCKET_ORDER_BY = "MAX(datetaken) DESC"
    
    uri = android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI
    
    val projection = arrayOf(MediaStore.Images.ImageColumns.BUCKET_ID,
            MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME,
            MediaStore.Images.ImageColumns.DATE_TAKEN,
            MediaStore.Images.ImageColumns.DATA)
    
    cursor = activity.contentResolver.query(uri, projection, BUCKET_GROUP_BY, null, BUCKET_ORDER_BY)
    
    if (cursor != null) {
        column_index_data = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA)
        column_index_folder_name = cursor
                .getColumnIndexOrThrow(MediaStore.Images.Media.BUCKET_DISPLAY_NAME)
        while (cursor.moveToNext()) {
            absolutePathOfImage = cursor.getString(column_index_data)
            Log.d("title_apps", "bucket name:" + cursor.getString(column_index_data))
    
            val selectionArgs = arrayOf("%" + cursor.getString(column_index_folder_name) + "%")
            val selection = MediaStore.Images.Media.DATA + " like ? "
            val projectionOnlyBucket = arrayOf(MediaStore.MediaColumns.DATA, MediaStore.Images.Media.BUCKET_DISPLAY_NAME)
    
            cursorBucket = activity.contentResolver.query(uri, projectionOnlyBucket, selection, selectionArgs, null)
            Log.d("title_apps", "bucket size:" + cursorBucket.count)
    
            if (absolutePathOfImage != "" && absolutePathOfImage != null) {
                listOfAllImages.add(absolutePathOfImage)
                albumsList.add(Albums(cursor.getString(column_index_folder_name), absolutePathOfImage, cursorBucket.count, false))
            }
        }
    }
    return getListOfVideoFolders(albumsList)
    }
    

    // 该函数负责读取所有文件夹中的所有视频。

    private fun getListOfVideoFolders(albumsList: ArrayList<Albums>): ArrayList<Albums> {
    var cursor: Cursor
    var cursorBucket: Cursor
    var uri: Uri
    val BUCKET_GROUP_BY = "1) GROUP BY 1,(2"
    val BUCKET_ORDER_BY = "MAX(datetaken) DESC"
    val column_index_album_name: Int
    val column_index_album_video: Int
    
    uri = android.provider.MediaStore.Video.Media.EXTERNAL_CONTENT_URI
    
    val projection1 = arrayOf(MediaStore.Video.VideoColumns.BUCKET_ID,
            MediaStore.Video.VideoColumns.BUCKET_DISPLAY_NAME,
            MediaStore.Video.VideoColumns.DATE_TAKEN,
            MediaStore.Video.VideoColumns.DATA)
    
    cursor = this.contentResolver.query(uri, projection1, BUCKET_GROUP_BY, null, BUCKET_ORDER_BY)
    
    if (cursor != null) {
        column_index_album_name = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.BUCKET_DISPLAY_NAME)
        column_index_album_video = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA)
        while (cursor.moveToNext()) {
            Log.d("title_apps", "bucket video:" + cursor.getString(column_index_album_name))
            Log.d("title_apps", "bucket video:" + cursor.getString(column_index_album_video))
            val selectionArgs = arrayOf("%" + cursor.getString(column_index_album_name) + "%")
    
            val selection = MediaStore.Video.Media.DATA + " like ? "
            val projectionOnlyBucket = arrayOf(MediaStore.MediaColumns.DATA, MediaStore.Video.Media.BUCKET_DISPLAY_NAME)
    
            cursorBucket = this.contentResolver.query(uri, projectionOnlyBucket, selection, selectionArgs, null)
            Log.d("title_apps", "bucket size:" + cursorBucket.count)
    
            albumsList.add(Albums(cursor.getString(column_index_album_name), cursor.getString(column_index_album_video), cursorBucket.count, true))
        }
    }
    return albumsList
    }
    

    【讨论】:

      【解决方案6】:

      您可以使用“IMediaColumns”代替“MediaColumns”。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-08-10
        • 1970-01-01
        • 2019-10-01
        • 2020-01-18
        • 2012-04-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多