Sửa lỗi failed to extract an album art trong android năm 2024

Album art is displayed normally in playlist and mini mode. However, other album art is displayed on the Now Playing screen.

Not all files show the wrong album art, but quite a few files cause this problem.

see this video.

Other players, such as JetAudio and Rocket Player, did not see this issue.

Sửa lỗi failed to extract an album art trong android năm 2024

Hello userW0THtCg6dX, thank you for reaching out to the Samsung Community. I understand you are getting an error when adding an album cover. Please attempt the following:

1. Clear the app cache and data on your device.

Open Settings, and then swipe to and tap Apps. Select or search for the app you want to clear. Tap Storage, and then tap Clear cache.

Android Auto Help

Sign in

Google Help

  • Help Center
  • Community
  • Android Auto
  • Privacy Policy
  • Terms of Service
  • Submit feedback

Send feedback on...

This help content & information

General Help Center experience

  • Help Center
  • Community

Android Auto

Để cung cấp trải nghiệm người dùng phong phú hơn, nhiều ứng dụng cho phép người dùng đóng góp và truy cập vào nội dung nghe nhìn có sẵn trong phương tiện (volume) bộ nhớ ngoài. Khung này cung cấp một chỉ mục được tối ưu hoá vào các bộ sưu tập nội dung nghe nhìn, gọi là kho nội dung nghe nhìn, giúp người dùng truy xuất và cập nhật các tệp nội dung nghe nhìn này dễ dàng hơn. Ngay cả khi ứng dụng của bạn đã bị gỡ cài đặt, những tệp này vẫn tồn tại trên thiết bị của người dùng.

Công cụ chọn ảnh

Thay vì sử dụng kho nội dung nghe nhìn, với công cụ chọn ảnh của Android, người dùng có một cách an toàn, tiện lợi để chọn các tệp nội dung nghe nhìn mà không cần cấp cho ứng dụng của bạn quyền truy cập vào toàn bộ thư viện nội dung nghe nhìn của họ. Tính năng này chỉ hoạt động trên các thiết bị được hỗ trợ. Để biết thêm thông tin, hãy xem hướng dẫn về công cụ chọn ảnh.

Để tương tác với tính năng trừu tượng của kho nội dung nghe nhìn, hãy sử dụng đối tượng

// Need the READ_EXTERNAL_STORAGE permission if accessing video files that your // app didn't create. // Container for information about each video. data class Video(val uri: Uri,

val name: String,
val duration: Int,
val size: Int
) val videoList = mutableListOf<Video>() 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
) // Show only videos that are at least 5 minutes in duration. val selection = "${MediaStore.Video.Media.DURATION} >= ?" val selectionArgs = arrayOf(
TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES).toString()
) // Display videos in alphabetical order based on their display name. val sortOrder = "${MediaStore.Video.Media.DISPLAY_NAME} ASC" val query = 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)
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 contentUri: Uri = ContentUris.withAppendedId(
        MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
        id
    )
    // Stores column values and the contentUri in a local object
    // that represents the media file.
    videoList += Video(contentUri, name, duration, size)
}
}

3 mà bạn truy xuất từ ngữ cảnh của ứng dụng:

Kotlin

val projection = arrayOf(media-database-columns-to-retrieve) val selection = sql-where-clause-with-placeholder-variables val selectionArgs = values-of-placeholder-variables val sortOrder = sql-order-by-clause applicationContext.contentResolver.query(

MediaStore.media-type.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
)?.use { cursor ->
while (cursor.moveToNext()) {
    // Use an ID column from the projection to get
    // a URI representing the media item itself.
}
}

Java

String[] projection = new String[] {

    media-database-columns-to-retrieve
}; String selection = sql-where-clause-with-placeholder-variables; String[] selectionArgs = new String[] {
    values-of-placeholder-variables
}; String sortOrder = sql-order-by-clause; Cursor cursor = getApplicationContext().getContentResolver().query(
MediaStore.media-type.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
); while (cursor.moveToNext()) {
// Use an ID column from the projection to get
// a URI representing the media item itself.
}

Hệ thống tự động quét phương tiện bộ nhớ ngoài và thêm các tệp phương tiện vào các bộ sưu tập được xác định rõ sau đây:

  • Hình ảnh, bao gồm cả ảnh chụp và ảnh chụp màn hình, được lưu trữ trong thư mục // Need the READ_EXTERNAL_STORAGE permission if accessing video files that your // app didn't create. // Container for information about each video. data class Video(val uri: Uri,
    val name: String,  
    val duration: Int,  
    val size: Int  
    
    ) val videoList = mutableListOf<Video>() 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  
    
    ) // Show only videos that are at least 5 minutes in duration. val selection = "${MediaStore.Video.Media.DURATION} >= ?" val selectionArgs = arrayOf(
    TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES).toString()  
    
    ) // Display videos in alphabetical order based on their display name. val sortOrder = "${MediaStore.Video.Media.DISPLAY_NAME} ASC" val query = 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)  
    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 contentUri: Uri = ContentUris.withAppendedId(  
            MediaStore.Video.Media.EXTERNAL_CONTENT_URI,  
            id  
        )  
        // Stores column values and the contentUri in a local object  
        // that represents the media file.  
        videoList += Video(contentUri, name, duration, size)  
    }  
    
    } 4 và // Need the READ_EXTERNAL_STORAGE permission if accessing video files that your // app didn't create. // Container for information about each video. data class Video(val uri: Uri,
    val name: String,  
    val duration: Int,  
    val size: Int  
    
    ) val videoList = mutableListOf<Video>() 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  
    
    ) // Show only videos that are at least 5 minutes in duration. val selection = "${MediaStore.Video.Media.DURATION} >= ?" val selectionArgs = arrayOf(
    TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES).toString()  
    
    ) // Display videos in alphabetical order based on their display name. val sortOrder = "${MediaStore.Video.Media.DISPLAY_NAME} ASC" val query = 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)  
    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 contentUri: Uri = ContentUris.withAppendedId(  
            MediaStore.Video.Media.EXTERNAL_CONTENT_URI,  
            id  
        )  
        // Stores column values and the contentUri in a local object  
        // that represents the media file.  
        videoList += Video(contentUri, name, duration, size)  
    }  
    
    } 5. Hệ thống sẽ thêm những tệp này vào bảng // Need the READ_EXTERNAL_STORAGE permission if accessing video files that your // app didn't create. // Container for information about each video. data class Video(val uri: Uri,
    val name: String,  
    val duration: Int,  
    val size: Int  
    
    ) val videoList = mutableListOf<Video>() 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  
    
    ) // Show only videos that are at least 5 minutes in duration. val selection = "${MediaStore.Video.Media.DURATION} >= ?" val selectionArgs = arrayOf(
    TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES).toString()  
    
    ) // Display videos in alphabetical order based on their display name. val sortOrder = "${MediaStore.Video.Media.DISPLAY_NAME} ASC" val query = 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)  
    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 contentUri: Uri = ContentUris.withAppendedId(  
            MediaStore.Video.Media.EXTERNAL_CONTENT_URI,  
            id  
        )  
        // Stores column values and the contentUri in a local object  
        // that represents the media file.  
        videoList += Video(contentUri, name, duration, size)  
    }  
    
    } 6.
  • Video, được lưu trữ trong thư mục // Need the READ_EXTERNAL_STORAGE permission if accessing video files that your // app didn't create. // Container for information about each video. data class Video(val uri: Uri,
    val name: String,  
    val duration: Int,  
    val size: Int  
    
    ) val videoList = mutableListOf<Video>() 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  
    
    ) // Show only videos that are at least 5 minutes in duration. val selection = "${MediaStore.Video.Media.DURATION} >= ?" val selectionArgs = arrayOf(
    TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES).toString()  
    
    ) // Display videos in alphabetical order based on their display name. val sortOrder = "${MediaStore.Video.Media.DISPLAY_NAME} ASC" val query = 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)  
    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 contentUri: Uri = ContentUris.withAppendedId(  
            MediaStore.Video.Media.EXTERNAL_CONTENT_URI,  
            id  
        )  
        // Stores column values and the contentUri in a local object  
        // that represents the media file.  
        videoList += Video(contentUri, name, duration, size)  
    }  
    
    } 4, // Need the READ_EXTERNAL_STORAGE permission if accessing video files that your // app didn't create. // Container for information about each video. data class Video(val uri: Uri,
    val name: String,  
    val duration: Int,  
    val size: Int  
    
    ) val videoList = mutableListOf<Video>() 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  
    
    ) // Show only videos that are at least 5 minutes in duration. val selection = "${MediaStore.Video.Media.DURATION} >= ?" val selectionArgs = arrayOf(
    TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES).toString()  
    
    ) // Display videos in alphabetical order based on their display name. val sortOrder = "${MediaStore.Video.Media.DISPLAY_NAME} ASC" val query = 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)  
    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 contentUri: Uri = ContentUris.withAppendedId(  
            MediaStore.Video.Media.EXTERNAL_CONTENT_URI,  
            id  
        )  
        // Stores column values and the contentUri in a local object  
        // that represents the media file.  
        videoList += Video(contentUri, name, duration, size)  
    }  
    
    } 8 và // Need the READ_EXTERNAL_STORAGE permission if accessing video files that your // app didn't create. // Container for information about each video. data class Video(val uri: Uri,
    val name: String,  
    val duration: Int,  
    val size: Int  
    
    ) val videoList = mutableListOf<Video>() 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  
    
    ) // Show only videos that are at least 5 minutes in duration. val selection = "${MediaStore.Video.Media.DURATION} >= ?" val selectionArgs = arrayOf(
    TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES).toString()  
    
    ) // Display videos in alphabetical order based on their display name. val sortOrder = "${MediaStore.Video.Media.DISPLAY_NAME} ASC" val query = 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)  
    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 contentUri: Uri = ContentUris.withAppendedId(  
            MediaStore.Video.Media.EXTERNAL_CONTENT_URI,  
            id  
        )  
        // Stores column values and the contentUri in a local object  
        // that represents the media file.  
        videoList += Video(contentUri, name, duration, size)  
    }  
    
    } 5. Hệ thống sẽ thêm những tệp này vào bảng // Need the READ_EXTERNAL_STORAGE permission if accessing video files that your // app didn't create. // Container for information about each video. class Video {
    private final Uri uri;  
    private final String name;  
    private final int duration;  
    private final int size;  
    public Video(Uri uri, String name, int duration, int size) {  
        this.uri = uri;  
        this.name = name;  
        this.duration = duration;  
        this.size = size;  
    }  
    
    } List<Video> videoList = new ArrayList<Video>(); Uri collection; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    collection = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);  
    
    } else {
    collection = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;  
    
    } String[] projection = new String[] {
    MediaStore.Video.Media._ID,  
    MediaStore.Video.Media.DISPLAY_NAME,  
    MediaStore.Video.Media.DURATION,  
    MediaStore.Video.Media.SIZE  
    
    }; String selection = MediaStore.Video.Media.DURATION +
        " >= ?";  
    
    String[] selectionArgs = new String[] {
    String.valueOf(TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES));  
    
    }; String sortOrder = MediaStore.Video.Media.DISPLAY_NAME + " ASC"; try (Cursor cursor = getApplicationContext().getContentResolver().query(
    collection,  
    projection,  
    selection,  
    selectionArgs,  
    sortOrder  
    
    )) {
    // Cache column indices.  
    int idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID);  
    int nameColumn =  
            cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME);  
    int durationColumn =  
            cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION);  
    int sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE);  
    while (cursor.moveToNext()) {  
        // Get values of columns for a given video.  
        long id = cursor.getLong(idColumn);  
        String name = cursor.getString(nameColumn);  
        int duration = cursor.getInt(durationColumn);  
        int size = cursor.getInt(sizeColumn);  
        Uri contentUri = ContentUris.withAppendedId(  
                MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id);  
        // Stores column values and the contentUri in a local object  
        // that represents the media file.  
        videoList.add(new Video(contentUri, name, duration, size));  
    }  
    
    } 0.
  • Tệp âm thanh, được lưu trữ trong thư mục // Need the READ_EXTERNAL_STORAGE permission if accessing video files that your // app didn't create. // Container for information about each video. class Video {
    private final Uri uri;  
    private final String name;  
    private final int duration;  
    private final int size;  
    public Video(Uri uri, String name, int duration, int size) {  
        this.uri = uri;  
        this.name = name;  
        this.duration = duration;  
        this.size = size;  
    }  
    
    } List<Video> videoList = new ArrayList<Video>(); Uri collection; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    collection = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);  
    
    } else {
    collection = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;  
    
    } String[] projection = new String[] {
    MediaStore.Video.Media._ID,  
    MediaStore.Video.Media.DISPLAY_NAME,  
    MediaStore.Video.Media.DURATION,  
    MediaStore.Video.Media.SIZE  
    
    }; String selection = MediaStore.Video.Media.DURATION +
        " >= ?";  
    
    String[] selectionArgs = new String[] {
    String.valueOf(TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES));  
    
    }; String sortOrder = MediaStore.Video.Media.DISPLAY_NAME + " ASC"; try (Cursor cursor = getApplicationContext().getContentResolver().query(
    collection,  
    projection,  
    selection,  
    selectionArgs,  
    sortOrder  
    
    )) {
    // Cache column indices.  
    int idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID);  
    int nameColumn =  
            cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME);  
    int durationColumn =  
            cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION);  
    int sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE);  
    while (cursor.moveToNext()) {  
        // Get values of columns for a given video.  
        long id = cursor.getLong(idColumn);  
        String name = cursor.getString(nameColumn);  
        int duration = cursor.getInt(durationColumn);  
        int size = cursor.getInt(sizeColumn);  
        Uri contentUri = ContentUris.withAppendedId(  
                MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id);  
        // Stores column values and the contentUri in a local object  
        // that represents the media file.  
        videoList.add(new Video(contentUri, name, duration, size));  
    }  
    
    } 1, // Need the READ_EXTERNAL_STORAGE permission if accessing video files that your // app didn't create. // Container for information about each video. class Video {
    private final Uri uri;  
    private final String name;  
    private final int duration;  
    private final int size;  
    public Video(Uri uri, String name, int duration, int size) {  
        this.uri = uri;  
        this.name = name;  
        this.duration = duration;  
        this.size = size;  
    }  
    
    } List<Video> videoList = new ArrayList<Video>(); Uri collection; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    collection = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);  
    
    } else {
    collection = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;  
    
    } String[] projection = new String[] {
    MediaStore.Video.Media._ID,  
    MediaStore.Video.Media.DISPLAY_NAME,  
    MediaStore.Video.Media.DURATION,  
    MediaStore.Video.Media.SIZE  
    
    }; String selection = MediaStore.Video.Media.DURATION +
        " >= ?";  
    
    String[] selectionArgs = new String[] {
    String.valueOf(TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES));  
    
    }; String sortOrder = MediaStore.Video.Media.DISPLAY_NAME + " ASC"; try (Cursor cursor = getApplicationContext().getContentResolver().query(
    collection,  
    projection,  
    selection,  
    selectionArgs,  
    sortOrder  
    
    )) {
    // Cache column indices.  
    int idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID);  
    int nameColumn =  
            cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME);  
    int durationColumn =  
            cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION);  
    int sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE);  
    while (cursor.moveToNext()) {  
        // Get values of columns for a given video.  
        long id = cursor.getLong(idColumn);  
        String name = cursor.getString(nameColumn);  
        int duration = cursor.getInt(durationColumn);  
        int size = cursor.getInt(sizeColumn);  
        Uri contentUri = ContentUris.withAppendedId(  
                MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id);  
        // Stores column values and the contentUri in a local object  
        // that represents the media file.  
        videoList.add(new Video(contentUri, name, duration, size));  
    }  
    
    } 2, // Need the READ_EXTERNAL_STORAGE permission if accessing video files that your // app didn't create. // Container for information about each video. class Video {
    private final Uri uri;  
    private final String name;  
    private final int duration;  
    private final int size;  
    public Video(Uri uri, String name, int duration, int size) {  
        this.uri = uri;  
        this.name = name;  
        this.duration = duration;  
        this.size = size;  
    }  
    
    } List<Video> videoList = new ArrayList<Video>(); Uri collection; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    collection = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);  
    
    } else {
    collection = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;  
    
    } String[] projection = new String[] {
    MediaStore.Video.Media._ID,  
    MediaStore.Video.Media.DISPLAY_NAME,  
    MediaStore.Video.Media.DURATION,  
    MediaStore.Video.Media.SIZE  
    
    }; String selection = MediaStore.Video.Media.DURATION +
        " >= ?";  
    
    String[] selectionArgs = new String[] {
    String.valueOf(TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES));  
    
    }; String sortOrder = MediaStore.Video.Media.DISPLAY_NAME + " ASC"; try (Cursor cursor = getApplicationContext().getContentResolver().query(
    collection,  
    projection,  
    selection,  
    selectionArgs,  
    sortOrder  
    
    )) {
    // Cache column indices.  
    int idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID);  
    int nameColumn =  
            cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME);  
    int durationColumn =  
            cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION);  
    int sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE);  
    while (cursor.moveToNext()) {  
        // Get values of columns for a given video.  
        long id = cursor.getLong(idColumn);  
        String name = cursor.getString(nameColumn);  
        int duration = cursor.getInt(durationColumn);  
        int size = cursor.getInt(sizeColumn);  
        Uri contentUri = ContentUris.withAppendedId(  
                MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id);  
        // Stores column values and the contentUri in a local object  
        // that represents the media file.  
        videoList.add(new Video(contentUri, name, duration, size));  
    }  
    
    } 3, // Need the READ_EXTERNAL_STORAGE permission if accessing video files that your // app didn't create. // Container for information about each video. class Video {
    private final Uri uri;  
    private final String name;  
    private final int duration;  
    private final int size;  
    public Video(Uri uri, String name, int duration, int size) {  
        this.uri = uri;  
        this.name = name;  
        this.duration = duration;  
        this.size = size;  
    }  
    
    } List<Video> videoList = new ArrayList<Video>(); Uri collection; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    collection = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);  
    
    } else {
    collection = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;  
    
    } String[] projection = new String[] {
    MediaStore.Video.Media._ID,  
    MediaStore.Video.Media.DISPLAY_NAME,  
    MediaStore.Video.Media.DURATION,  
    MediaStore.Video.Media.SIZE  
    
    }; String selection = MediaStore.Video.Media.DURATION +
        " >= ?";  
    
    String[] selectionArgs = new String[] {
    String.valueOf(TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES));  
    
    }; String sortOrder = MediaStore.Video.Media.DISPLAY_NAME + " ASC"; try (Cursor cursor = getApplicationContext().getContentResolver().query(
    collection,  
    projection,  
    selection,  
    selectionArgs,  
    sortOrder  
    
    )) {
    // Cache column indices.  
    int idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID);  
    int nameColumn =  
            cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME);  
    int durationColumn =  
            cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION);  
    int sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE);  
    while (cursor.moveToNext()) {  
        // Get values of columns for a given video.  
        long id = cursor.getLong(idColumn);  
        String name = cursor.getString(nameColumn);  
        int duration = cursor.getInt(durationColumn);  
        int size = cursor.getInt(sizeColumn);  
        Uri contentUri = ContentUris.withAppendedId(  
                MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id);  
        // Stores column values and the contentUri in a local object  
        // that represents the media file.  
        videoList.add(new Video(contentUri, name, duration, size));  
    }  
    
    } 4, // Need the READ_EXTERNAL_STORAGE permission if accessing video files that your // app didn't create. // Container for information about each video. class Video {
    private final Uri uri;  
    private final String name;  
    private final int duration;  
    private final int size;  
    public Video(Uri uri, String name, int duration, int size) {  
        this.uri = uri;  
        this.name = name;  
        this.duration = duration;  
        this.size = size;  
    }  
    
    } List<Video> videoList = new ArrayList<Video>(); Uri collection; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    collection = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);  
    
    } else {
    collection = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;  
    
    } String[] projection = new String[] {
    MediaStore.Video.Media._ID,  
    MediaStore.Video.Media.DISPLAY_NAME,  
    MediaStore.Video.Media.DURATION,  
    MediaStore.Video.Media.SIZE  
    
    }; String selection = MediaStore.Video.Media.DURATION +
        " >= ?";  
    
    String[] selectionArgs = new String[] {
    String.valueOf(TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES));  
    
    }; String sortOrder = MediaStore.Video.Media.DISPLAY_NAME + " ASC"; try (Cursor cursor = getApplicationContext().getContentResolver().query(
    collection,  
    projection,  
    selection,  
    selectionArgs,  
    sortOrder  
    
    )) {
    // Cache column indices.  
    int idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID);  
    int nameColumn =  
            cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME);  
    int durationColumn =  
            cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION);  
    int sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE);  
    while (cursor.moveToNext()) {  
        // Get values of columns for a given video.  
        long id = cursor.getLong(idColumn);  
        String name = cursor.getString(nameColumn);  
        int duration = cursor.getInt(durationColumn);  
        int size = cursor.getInt(sizeColumn);  
        Uri contentUri = ContentUris.withAppendedId(  
                MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id);  
        // Stores column values and the contentUri in a local object  
        // that represents the media file.  
        videoList.add(new Video(contentUri, name, duration, size));  
    }  
    
    } 5 và // Need the READ_EXTERNAL_STORAGE permission if accessing video files that your // app didn't create. // Container for information about each video. class Video {
    private final Uri uri;  
    private final String name;  
    private final int duration;  
    private final int size;  
    public Video(Uri uri, String name, int duration, int size) {  
        this.uri = uri;  
        this.name = name;  
        this.duration = duration;  
        this.size = size;  
    }  
    
    } List<Video> videoList = new ArrayList<Video>(); Uri collection; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    collection = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);  
    
    } else {
    collection = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;  
    
    } String[] projection = new String[] {
    MediaStore.Video.Media._ID,  
    MediaStore.Video.Media.DISPLAY_NAME,  
    MediaStore.Video.Media.DURATION,  
    MediaStore.Video.Media.SIZE  
    
    }; String selection = MediaStore.Video.Media.DURATION +
        " >= ?";  
    
    String[] selectionArgs = new String[] {
    String.valueOf(TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES));  
    
    }; String sortOrder = MediaStore.Video.Media.DISPLAY_NAME + " ASC"; try (Cursor cursor = getApplicationContext().getContentResolver().query(
    collection,  
    projection,  
    selection,  
    selectionArgs,  
    sortOrder  
    
    )) {
    // Cache column indices.  
    int idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID);  
    int nameColumn =  
            cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME);  
    int durationColumn =  
            cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION);  
    int sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE);  
    while (cursor.moveToNext()) {  
        // Get values of columns for a given video.  
        long id = cursor.getLong(idColumn);  
        String name = cursor.getString(nameColumn);  
        int duration = cursor.getInt(durationColumn);  
        int size = cursor.getInt(sizeColumn);  
        Uri contentUri = ContentUris.withAppendedId(  
                MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id);  
        // Stores column values and the contentUri in a local object  
        // that represents the media file.  
        videoList.add(new Video(contentUri, name, duration, size));  
    }  
    
    } 6. Ngoài ra, hệ thống ghi nhận các danh sách phát âm thanh trong thư mục // Need the READ_EXTERNAL_STORAGE permission if accessing video files that your // app didn't create. // Container for information about each video. class Video {
    private final Uri uri;  
    private final String name;  
    private final int duration;  
    private final int size;  
    public Video(Uri uri, String name, int duration, int size) {  
        this.uri = uri;  
        this.name = name;  
        this.duration = duration;  
        this.size = size;  
    }  
    
    } List<Video> videoList = new ArrayList<Video>(); Uri collection; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    collection = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);  
    
    } else {
    collection = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;  
    
    } String[] projection = new String[] {
    MediaStore.Video.Media._ID,  
    MediaStore.Video.Media.DISPLAY_NAME,  
    MediaStore.Video.Media.DURATION,  
    MediaStore.Video.Media.SIZE  
    
    }; String selection = MediaStore.Video.Media.DURATION +
        " >= ?";  
    
    String[] selectionArgs = new String[] {
    String.valueOf(TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES));  
    
    }; String sortOrder = MediaStore.Video.Media.DISPLAY_NAME + " ASC"; try (Cursor cursor = getApplicationContext().getContentResolver().query(
    collection,  
    projection,  
    selection,  
    selectionArgs,  
    sortOrder  
    
    )) {
    // Cache column indices.  
    int idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID);  
    int nameColumn =  
            cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME);  
    int durationColumn =  
            cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION);  
    int sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE);  
    while (cursor.moveToNext()) {  
        // Get values of columns for a given video.  
        long id = cursor.getLong(idColumn);  
        String name = cursor.getString(nameColumn);  
        int duration = cursor.getInt(durationColumn);  
        int size = cursor.getInt(sizeColumn);  
        Uri contentUri = ContentUris.withAppendedId(  
                MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id);  
        // Stores column values and the contentUri in a local object  
        // that represents the media file.  
        videoList.add(new Video(contentUri, name, duration, size));  
    }  
    
    } 3 hoặc // Need the READ_EXTERNAL_STORAGE permission if accessing video files that your // app didn't create. // Container for information about each video. data class Video(val uri: Uri,
    val name: String,  
    val duration: Int,  
    val size: Int  
    
    ) val videoList = mutableListOf<Video>() 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  
    
    ) // Show only videos that are at least 5 minutes in duration. val selection = "${MediaStore.Video.Media.DURATION} >= ?" val selectionArgs = arrayOf(
    TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES).toString()  
    
    ) // Display videos in alphabetical order based on their display name. val sortOrder = "${MediaStore.Video.Media.DISPLAY_NAME} ASC" val query = 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)  
    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 contentUri: Uri = ContentUris.withAppendedId(  
            MediaStore.Video.Media.EXTERNAL_CONTENT_URI,  
            id  
        )  
        // Stores column values and the contentUri in a local object  
        // that represents the media file.  
        videoList += Video(contentUri, name, duration, size)  
    }  
    
    } 8, cũng như các bản ghi âm giọng nói nằm trong thư mục // Need the READ_EXTERNAL_STORAGE permission if accessing video files that your // app didn't create. // Container for information about each video. class Video {
    private final Uri uri;  
    private final String name;  
    private final int duration;  
    private final int size;  
    public Video(Uri uri, String name, int duration, int size) {  
        this.uri = uri;  
        this.name = name;  
        this.duration = duration;  
        this.size = size;  
    }  
    
    } List<Video> videoList = new ArrayList<Video>(); Uri collection; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    collection = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);  
    
    } else {
    collection = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;  
    
    } String[] projection = new String[] {
    MediaStore.Video.Media._ID,  
    MediaStore.Video.Media.DISPLAY_NAME,  
    MediaStore.Video.Media.DURATION,  
    MediaStore.Video.Media.SIZE  
    
    }; String selection = MediaStore.Video.Media.DURATION +
        " >= ?";  
    
    String[] selectionArgs = new String[] {
    String.valueOf(TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES));  
    
    }; String sortOrder = MediaStore.Video.Media.DISPLAY_NAME + " ASC"; try (Cursor cursor = getApplicationContext().getContentResolver().query(
    collection,  
    projection,  
    selection,  
    selectionArgs,  
    sortOrder  
    
    )) {
    // Cache column indices.  
    int idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID);  
    int nameColumn =  
            cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME);  
    int durationColumn =  
            cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION);  
    int sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE);  
    while (cursor.moveToNext()) {  
        // Get values of columns for a given video.  
        long id = cursor.getLong(idColumn);  
        String name = cursor.getString(nameColumn);  
        int duration = cursor.getInt(durationColumn);  
        int size = cursor.getInt(sizeColumn);  
        Uri contentUri = ContentUris.withAppendedId(  
                MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id);  
        // Stores column values and the contentUri in a local object  
        // that represents the media file.  
        videoList.add(new Video(contentUri, name, duration, size));  
    }  
    
    } 9. Hệ thống sẽ thêm những tệp này vào bảng // Load thumbnail of a specific media item. val thumbnail: Bitmap =
        applicationContext.contentResolver.loadThumbnail(  
        content-uri, Size(640, 480), null)  
    
    0. Không có thư mục // Need the READ_EXTERNAL_STORAGE permission if accessing video files that your // app didn't create. // Container for information about each video. class Video {
    private final Uri uri;  
    private final String name;  
    private final int duration;  
    private final int size;  
    public Video(Uri uri, String name, int duration, int size) {  
        this.uri = uri;  
        this.name = name;  
        this.duration = duration;  
        this.size = size;  
    }  
    
    } List<Video> videoList = new ArrayList<Video>(); Uri collection; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    collection = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);  
    
    } else {
    collection = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;  
    
    } String[] projection = new String[] {
    MediaStore.Video.Media._ID,  
    MediaStore.Video.Media.DISPLAY_NAME,  
    MediaStore.Video.Media.DURATION,  
    MediaStore.Video.Media.SIZE  
    
    }; String selection = MediaStore.Video.Media.DURATION +
        " >= ?";  
    
    String[] selectionArgs = new String[] {
    String.valueOf(TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES));  
    
    }; String sortOrder = MediaStore.Video.Media.DISPLAY_NAME + " ASC"; try (Cursor cursor = getApplicationContext().getContentResolver().query(
    collection,  
    projection,  
    selection,  
    selectionArgs,  
    sortOrder  
    
    )) {
    // Cache column indices.  
    int idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID);  
    int nameColumn =  
            cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME);  
    int durationColumn =  
            cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION);  
    int sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE);  
    while (cursor.moveToNext()) {  
        // Get values of columns for a given video.  
        long id = cursor.getLong(idColumn);  
        String name = cursor.getString(nameColumn);  
        int duration = cursor.getInt(durationColumn);  
        int size = cursor.getInt(sizeColumn);  
        Uri contentUri = ContentUris.withAppendedId(  
                MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id);  
        // Stores column values and the contentUri in a local object  
        // that represents the media file.  
        videoList.add(new Video(contentUri, name, duration, size));  
    }  
    
    } 9 trong Android 11 (API cấp 30) trở xuống.
  • Tệp đã tải xuống, được lưu trữ trong thư mục // Load thumbnail of a specific media item. val thumbnail: Bitmap =
        applicationContext.contentResolver.loadThumbnail(  
        content-uri, Size(640, 480), null)  
    
    2. Trên các thiết bị chạy Android 10 (API cấp 29) trở lên, những tệp này được lưu trữ trong bảng // Load thumbnail of a specific media item. val thumbnail: Bitmap =
        applicationContext.contentResolver.loadThumbnail(  
        content-uri, Size(640, 480), null)  
    
    3. Không có bảng này trên Android 9 (API cấp 28) trở xuống.

Kho nội dung nghe nhìn cũng bao gồm một bộ sưu tập có tên là

// Load thumbnail of a specific media item. val thumbnail: Bitmap =

    applicationContext.contentResolver.loadThumbnail(
    content-uri, Size(640, 480), null)
4. Nội dung của bộ sưu tập này tuỳ thuộc vào việc ứng dụng của bạn có dùng có sẵn trên các ứng dụng nhắm mục tiêu đến Android 10 trở lên hay không.

  • Nếu tính năng bộ nhớ có giới hạn được bật, bộ sưu tập sẽ chỉ hiển thị ảnh, video và các tệp âm thanh mà ứng dụng của bạn đã tạo. Hầu hết các nhà phát triển không cần sử dụng // Load thumbnail of a specific media item. val thumbnail: Bitmap =
        applicationContext.contentResolver.loadThumbnail(  
        content-uri, Size(640, 480), null)  
    
    4 để xem các tệp nội dung nghe nhìn từ các ứng dụng khác nhưng nếu có yêu cầu cụ thể về việc này, bạn có thể khai báo quyền // Load thumbnail of a specific media item. val thumbnail: Bitmap =
        applicationContext.contentResolver.loadThumbnail(  
        content-uri, Size(640, 480), null)  
    
    6. Tuy nhiên, bạn nên sử dụng các API // Load thumbnail of a specific media item. val thumbnail: Bitmap =
        applicationContext.contentResolver.loadThumbnail(  
        content-uri, Size(640, 480), null)  
    
    7 để mà ứng dụng của bạn chưa tạo.
  • Nếu bộ nhớ có giới hạn không có sẵn hoặc không được sử dụng, bộ sưu tập sẽ hiển thị tất cả các loại tệp nội dung nghe nhìn.

Yêu cầu cấp các quyền cần thiết

Trước khi thực hiện các thao tác đối với tệp nội dung nghe nhìn, hãy đảm bảo ứng dụng của bạn đã khai báo các quyền cần thiết để truy cập vào các tệp này. Tuy nhiên, hãy lưu ý không khai báo các quyền mà ứng dụng không cần hoặc không sử dụng.

Quyền truy cập vào bộ nhớ

Việc ứng dụng của bạn có cần quyền truy cập vào bộ nhớ hay không tuỳ thuộc vào việc ứng dụng đó chỉ truy cập vào các tệp nội dung nghe nhìn của riêng ứng dụng đó hay các tệp do các ứng dụng khác tạo ra.

Truy cập vào tệp nội dung nghe nhìn của riêng bạn

Trên các thiết bị chạy Android 10 trở lên, bạn không cần quyền liên quan đến bộ nhớ để truy cập và sửa đổi các tệp nội dung nghe nhìn mà , bao gồm cả các tệp trong bộ sưu tập

// Load thumbnail of a specific media item. val thumbnail: Bitmap =

    applicationContext.contentResolver.loadThumbnail(
    content-uri, Size(640, 480), null)
3. Ví dụ: nếu đang phát triển một ứng dụng máy ảnh, thì bạn không cần yêu cầu các quyền liên quan đến bộ nhớ để truy cập vào ảnh cần chụp, vì ứng dụng của bạn sở hữu những hình ảnh mà bạn đang ghi vào kho nội dung nghe nhìn.

Truy cập vào tệp nội dung nghe nhìn của các ứng dụng khác

Để truy cập vào tệp nội dung nghe nhìn mà các ứng dụng khác tạo ra, bạn phải khai báo các quyền phù hợp liên quan đến bộ nhớ, đồng thời các tệp đó phải thuộc một trong các bộ sưu tập nội dung nghe nhìn sau đây:

  • // Need the READ_EXTERNAL_STORAGE permission if accessing video files that your // app didn't create. // Container for information about each video. data class Video(val uri: Uri,
    val name: String,  
    val duration: Int,  
    val size: Int  
    
    ) val videoList = mutableListOf<Video>() 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  
    
    ) // Show only videos that are at least 5 minutes in duration. val selection = "${MediaStore.Video.Media.DURATION} >= ?" val selectionArgs = arrayOf(
    TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES).toString()  
    
    ) // Display videos in alphabetical order based on their display name. val sortOrder = "${MediaStore.Video.Media.DISPLAY_NAME} ASC" val query = 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)  
    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 contentUri: Uri = ContentUris.withAppendedId(  
            MediaStore.Video.Media.EXTERNAL_CONTENT_URI,  
            id  
        )  
        // Stores column values and the contentUri in a local object  
        // that represents the media file.  
        videoList += Video(contentUri, name, duration, size)  
    }  
    
    } 6
  • // Need the READ_EXTERNAL_STORAGE permission if accessing video files that your // app didn't create. // Container for information about each video. class Video {
    private final Uri uri;  
    private final String name;  
    private final int duration;  
    private final int size;  
    public Video(Uri uri, String name, int duration, int size) {  
        this.uri = uri;  
        this.name = name;  
        this.duration = duration;  
        this.size = size;  
    }  
    
    } List<Video> videoList = new ArrayList<Video>(); Uri collection; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    collection = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);  
    
    } else {
    collection = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;  
    
    } String[] projection = new String[] {
    MediaStore.Video.Media._ID,  
    MediaStore.Video.Media.DISPLAY_NAME,  
    MediaStore.Video.Media.DURATION,  
    MediaStore.Video.Media.SIZE  
    
    }; String selection = MediaStore.Video.Media.DURATION +
        " >= ?";  
    
    String[] selectionArgs = new String[] {
    String.valueOf(TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES));  
    
    }; String sortOrder = MediaStore.Video.Media.DISPLAY_NAME + " ASC"; try (Cursor cursor = getApplicationContext().getContentResolver().query(
    collection,  
    projection,  
    selection,  
    selectionArgs,  
    sortOrder  
    
    )) {
    // Cache column indices.  
    int idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID);  
    int nameColumn =  
            cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME);  
    int durationColumn =  
            cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION);  
    int sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE);  
    while (cursor.moveToNext()) {  
        // Get values of columns for a given video.  
        long id = cursor.getLong(idColumn);  
        String name = cursor.getString(nameColumn);  
        int duration = cursor.getInt(durationColumn);  
        int size = cursor.getInt(sizeColumn);  
        Uri contentUri = ContentUris.withAppendedId(  
                MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id);  
        // Stores column values and the contentUri in a local object  
        // that represents the media file.  
        videoList.add(new Video(contentUri, name, duration, size));  
    }  
    
    } 0
  • // Load thumbnail of a specific media item. val thumbnail: Bitmap =
        applicationContext.contentResolver.loadThumbnail(  
        content-uri, Size(640, 480), null)  
    
    0

Miễn là một tệp có thể xem được bằng truy vấn

// Need the READ_EXTERNAL_STORAGE permission if accessing video files that your // app didn't create. // Container for information about each video. data class Video(val uri: Uri,

val name: String,
val duration: Int,
val size: Int
) val videoList = mutableListOf<Video>() 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
) // Show only videos that are at least 5 minutes in duration. val selection = "${MediaStore.Video.Media.DURATION} >= ?" val selectionArgs = arrayOf(
TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES).toString()
) // Display videos in alphabetical order based on their display name. val sortOrder = "${MediaStore.Video.Media.DISPLAY_NAME} ASC" val query = 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)
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 contentUri: Uri = ContentUris.withAppendedId(
        MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
        id
    )
    // Stores column values and the contentUri in a local object
    // that represents the media file.
    videoList += Video(contentUri, name, duration, size)
}
}

6,

// Need the READ_EXTERNAL_STORAGE permission if accessing video files that your // app didn't create. // Container for information about each video. class Video {

private final Uri uri;
private final String name;
private final int duration;
private final int size;
public Video(Uri uri, String name, int duration, int size) {
    this.uri = uri;
    this.name = name;
    this.duration = duration;
    this.size = size;
}
} List<Video> videoList = new ArrayList<Video>(); Uri collection; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
collection = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);
} else {
collection = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} String[] projection = new String[] {
MediaStore.Video.Media._ID,
MediaStore.Video.Media.DISPLAY_NAME,
MediaStore.Video.Media.DURATION,
MediaStore.Video.Media.SIZE
}; String selection = MediaStore.Video.Media.DURATION +
    " >= ?";
String[] selectionArgs = new String[] {
String.valueOf(TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES));
}; String sortOrder = MediaStore.Video.Media.DISPLAY_NAME + " ASC"; try (Cursor cursor = getApplicationContext().getContentResolver().query(
collection,
projection,
selection,
selectionArgs,
sortOrder
)) {
// Cache column indices.
int idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID);
int nameColumn =
        cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME);
int durationColumn =
        cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION);
int sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE);
while (cursor.moveToNext()) {
    // Get values of columns for a given video.
    long id = cursor.getLong(idColumn);
    String name = cursor.getString(nameColumn);
    int duration = cursor.getInt(durationColumn);
    int size = cursor.getInt(sizeColumn);
    Uri contentUri = ContentUris.withAppendedId(
            MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id);
    // Stores column values and the contentUri in a local object
    // that represents the media file.
    videoList.add(new Video(contentUri, name, duration, size));
}
}

0 hoặc

// Load thumbnail of a specific media item. val thumbnail: Bitmap =

    applicationContext.contentResolver.loadThumbnail(
    content-uri, Size(640, 480), null)
0, thì tệp đó cũng có thể xem được bằng truy vấn

// Load thumbnail of a specific media item. val thumbnail: Bitmap =

    applicationContext.contentResolver.loadThumbnail(
    content-uri, Size(640, 480), null)
4.

Đoạn mã sau đây minh hoạ cách khai báo quyền phù hợp liên quan đến bộ nhớ:

<! Required only if your app needs to access images or photos

 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <! Required only if your app needs to access videos
 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <!-- Required only if your app needs to access audio files
 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
             android:maxSdkVersion="29" />
Nếu ứng dụng của bạn được dùng trên một thiết bị chạy Android 9 trở xuống hoặc tạm thời , thì bạn phải yêu cầu quyền để truy cập vào bất cứ tệp nội dung nghe nhìn nào. Nếu muốn sửa đổi các tệp nội dung nghe nhìn, thì bạn cũng phải yêu cầu quyền .

Yêu cầu Khung truy cập bộ nhớ để truy cập nội dung tải xuống của ứng dụng khác

Nếu ứng dụng của bạn muốn truy cập vào một tệp trong bộ sưu tập

// Load thumbnail of a specific media item. val thumbnail: Bitmap =

    applicationContext.contentResolver.loadThumbnail(
    content-uri, Size(640, 480), null)
3 mà ứng dụng không tạo, thì bạn phải sử dụng Khung truy cập bộ nhớ (Storage Access Framework). Để tìm hiểu thêm về cách sử dụng khung này, hãy xem phần Truy cập vào tài liệu và các tệp khác trong bộ nhớ dùng chung.

Quyền truy cập thông tin vị trí của nội dung nghe nhìn

Nếu ứng dụng của bạn nhắm mục tiêu đến Android 10 (API cấp 29) trở lên và cần phải truy xuất siêu dữ liệu EXIF chưa bị che khuất từ các ảnh, bạn cần khai báo quyền trong tệp kê khai của ứng dụng, sau đó yêu cầu quyền này trong thời gian chạy.

Kiểm tra để tìm các bản cập nhật cho kho nội dung nghe nhìn

Để truy cập vào các tệp phương tiện một cách đáng tin cậy hơn, đặc biệt khi ứng dụng của bạn lưu URI hoặc dữ liệu từ kho phương tiện vào bộ nhớ đệm, hãy kiểm tra xem phiên bản kho phương tiện có thay đổi so với lần đồng bộ hoá dữ liệu nội dung phương tiện gần đây nhất hay không. Để thực hiện kiểm tra các bản cập nhật này, hãy gọi . Phiên bản được trả về là một chuỗi duy nhất sẽ thay đổi mỗi khi kho phương tiện thay đổi đáng kể. Nếu phiên bản được trả về khác với phiên bản đã đồng bộ hoá gần đây nhất, hãy quét lại và đồng bộ hoá lại bộ nhớ đệm chứa nội dung phương tiện của ứng dụng.

Hoàn thành thao tác kiểm tra này vào thời điểm khởi động quy trình ứng dụng. Bạn không cần kiểm tra phiên bản mỗi lần truy vấn kho phương tiện.

Không giả định bất kỳ chi tiết triển khai nào liên quan đến số phiên bản.

Truy vấn bộ sưu tập nội dung nghe nhìn

Để tìm nội dung nghe nhìn đáp ứng một nhóm điều kiện cụ thể, chẳng hạn như có thời lượng 5 phút trở lên, hãy sử dụng câu lệnh lựa chọn giống như SQL, tương tự như câu lệnh được minh hoạ trong đoạn mã sau đây:

Kotlin

// Need the READ_EXTERNAL_STORAGE permission if accessing video files that your // app didn't create. // Container for information about each video. data class Video(val uri: Uri,

val name: String,
val duration: Int,
val size: Int
) val videoList = mutableListOf<Video>() 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
) // Show only videos that are at least 5 minutes in duration. val selection = "${MediaStore.Video.Media.DURATION} >= ?" val selectionArgs = arrayOf(
TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES).toString()
) // Display videos in alphabetical order based on their display name. val sortOrder = "${MediaStore.Video.Media.DISPLAY_NAME} ASC" val query = 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)
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 contentUri: Uri = ContentUris.withAppendedId(
        MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
        id
    )
    // Stores column values and the contentUri in a local object
    // that represents the media file.
    videoList += Video(contentUri, name, duration, size)
}
}

Java

// Need the READ_EXTERNAL_STORAGE permission if accessing video files that your // app didn't create. // Container for information about each video. class Video {

private final Uri uri;
private final String name;
private final int duration;
private final int size;
public Video(Uri uri, String name, int duration, int size) {
    this.uri = uri;
    this.name = name;
    this.duration = duration;
    this.size = size;
}
} List<Video> videoList = new ArrayList<Video>(); Uri collection; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
collection = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);
} else {
collection = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} String[] projection = new String[] {
MediaStore.Video.Media._ID,
MediaStore.Video.Media.DISPLAY_NAME,
MediaStore.Video.Media.DURATION,
MediaStore.Video.Media.SIZE
}; String selection = MediaStore.Video.Media.DURATION +
    " >= ?";
String[] selectionArgs = new String[] {
String.valueOf(TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES));
}; String sortOrder = MediaStore.Video.Media.DISPLAY_NAME + " ASC"; try (Cursor cursor = getApplicationContext().getContentResolver().query(
collection,
projection,
selection,
selectionArgs,
sortOrder
)) {
// Cache column indices.
int idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID);
int nameColumn =
        cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME);
int durationColumn =
        cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION);
int sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE);
while (cursor.moveToNext()) {
    // Get values of columns for a given video.
    long id = cursor.getLong(idColumn);
    String name = cursor.getString(nameColumn);
    int duration = cursor.getInt(durationColumn);
    int size = cursor.getInt(sizeColumn);
    Uri contentUri = ContentUris.withAppendedId(
            MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id);
    // Stores column values and the contentUri in a local object
    // that represents the media file.
    videoList.add(new Video(contentUri, name, duration, size));
}
}

Khi thực hiện truy vấn kiểu này trong ứng dụng của bạn, hãy lưu ý những điều sau:

  • Gọi phương thức // Open a specific media item using ParcelFileDescriptor. val resolver = applicationContext.contentResolver // "rw" for read-and-write. // "rwt" for truncating or overwriting existing file contents. val readOnlyMode = "r" resolver.openFileDescriptor(content-uri, readOnlyMode).use { pfd ->
    // Perform operations on "pfd".  
    
    } 1 trong một luồng woker.
  • Lưu các chỉ mục cột vào bộ nhớ đệm để bạn không cần gọi mỗi khi xử lý một hàng từ kết quả truy vấn.
  • Nối mã nhận dạng (ID) vào URI nội dung như trong ví dụ này.
  • Các thiết bị chạy Android 10 trở lên yêu cầu tên cột được xác định trong API // Load thumbnail of a specific media item. val thumbnail: Bitmap =
        applicationContext.contentResolver.loadThumbnail(  
        content-uri, Size(640, 480), null)  
    
    7. Nếu một thư viện phụ thuộc trong ứng dụng của bạn dự kiến có tên cột không xác định trong API, chẳng hạn như // Open a specific media item using ParcelFileDescriptor. val resolver = applicationContext.contentResolver // "rw" for read-and-write. // "rwt" for truncating or overwriting existing file contents. val readOnlyMode = "r" resolver.openFileDescriptor(content-uri, readOnlyMode).use { pfd ->
    // Perform operations on "pfd".  
    
    } 4, hãy sử dụng // Open a specific media item using ParcelFileDescriptor. val resolver = applicationContext.contentResolver // "rw" for read-and-write. // "rwt" for truncating or overwriting existing file contents. val readOnlyMode = "r" resolver.openFileDescriptor(content-uri, readOnlyMode).use { pfd ->
    // Perform operations on "pfd".  
    
    } 5 để linh động dịch tên cột trong quá trình của ứng dụng.

Tải hình thu nhỏ của tệp

Nếu ứng dụng của bạn hiển thị nhiều tệp nội dung nghe nhìn và yêu cầu người dùng chọn một trong các tệp này, thì việc tải phiên bản xem trước (hay hình thu nhỏ) của các tệp sẽ hiệu quả hơn thay vì tải chính các tệp.

Để tải hình thu nhỏ của một tệp nội dung nghe nhìn cụ thể, hãy sử dụng và truyền vào đó kích thước hình thu nhỏ mà bạn muốn tải, như minh hoạ trong đoạn mã sau đây:

Kotlin

// Load thumbnail of a specific media item. val thumbnail: Bitmap =

    applicationContext.contentResolver.loadThumbnail(
    content-uri, Size(640, 480), null)

Java

// Load thumbnail of a specific media item. Bitmap thumbnail =

    getApplicationContext().getContentResolver().loadThumbnail(
    content-uri, new Size(640, 480), null);

Mở một tệp nội dung nghe nhìn

Logic cụ thể mà bạn sử dụng để mở tệp nội dung nghe nhìn phụ thuộc vào việc nội dung nghe nhìn được thể hiện tốt nhất dưới dạng chỉ số mô tả tệp, luồng tệp hay đường dẫn tệp trực tiếp:

Chỉ số mô tả tệp

Để mở tệp phương tiện bằng chỉ số mô tả tệp, hãy sử dụng logic tương tự như logic trong đoạn mã sau đây:

Kotlin

// Open a specific media item using ParcelFileDescriptor. val resolver = applicationContext.contentResolver // "rw" for read-and-write. // "rwt" for truncating or overwriting existing file contents. val readOnlyMode = "r" resolver.openFileDescriptor(content-uri, readOnlyMode).use { pfd ->

// Perform operations on "pfd".
}

Java

// Open a specific media item using ParcelFileDescriptor. ContentResolver resolver = getApplicationContext()

    .getContentResolver();
// "rw" for read-and-write. // "rwt" for truncating or overwriting existing file contents. String readOnlyMode = "r"; try (ParcelFileDescriptor pfd =
    resolver.openFileDescriptor(content-uri, readOnlyMode)) {
// Perform operations on "pfd".
} catch (IOException e) {
e.printStackTrace();
}

Luồng tệp

Để mở tệp phương tiện bằng luồng tệp, hãy sử dụng logic tương tự như logic trong đoạn mã sau đây:

Kotlin

// Open a specific media item using InputStream. val resolver = applicationContext.contentResolver resolver.openInputStream(content-uri).use { stream ->

// Perform operations on "stream".
}

Java

String[] projection = new String[] {

    media-database-columns-to-retrieve
}; String selection = sql-where-clause-with-placeholder-variables; String[] selectionArgs = new String[] {
    values-of-placeholder-variables
}; String sortOrder = sql-order-by-clause; Cursor cursor = getApplicationContext().getContentResolver().query(
MediaStore.media-type.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
); while (cursor.moveToNext()) {
// Use an ID column from the projection to get
// a URI representing the media item itself.
}

0

Đường dẫn tệp trực tiếp

Để giúp ứng dụng của bạn hoạt động trơn tru hơn với thư viện nội dung nghe nhìn của bên thứ ba, Android 11 (API cấp 30) trở lên cho phép bạn sử dụng các API trừ API

// Load thumbnail of a specific media item. val thumbnail: Bitmap =

    applicationContext.contentResolver.loadThumbnail(
    content-uri, Size(640, 480), null)
7 để truy cập vào tệp nội dung nghe nhìn từ bộ nhớ dùng chung. Thay vào đó, bạn có thể truy cập trực tiếp vào các tệp nội dung nghe nhìn bằng một trong các API sau đây:

  • API // Open a specific media item using ParcelFileDescriptor. val resolver = applicationContext.contentResolver // "rw" for read-and-write. // "rwt" for truncating or overwriting existing file contents. val readOnlyMode = "r" resolver.openFileDescriptor(content-uri, readOnlyMode).use { pfd ->
    // Perform operations on "pfd".  
    
    } 8
  • Các thư viện gốc, chẳng hạn như // Open a specific media item using ParcelFileDescriptor. val resolver = applicationContext.contentResolver // "rw" for read-and-write. // "rwt" for truncating or overwriting existing file contents. val readOnlyMode = "r" resolver.openFileDescriptor(content-uri, readOnlyMode).use { pfd ->
    // Perform operations on "pfd".  
    
    } 9

Nếu không có bất kỳ quyền liên quan đến bộ nhớ nào, bạn có thể truy cập vào các tệp trong thư mục dành riêng cho ứng dụng, cũng như bằng API

// Open a specific media item using ParcelFileDescriptor. val resolver = applicationContext.contentResolver // "rw" for read-and-write. // "rwt" for truncating or overwriting existing file contents. val readOnlyMode = "r" resolver.openFileDescriptor(content-uri, readOnlyMode).use { pfd ->

// Perform operations on "pfd".
}

8.

Nếu ứng dụng của bạn cố gắng truy cập vào một tệp bằng API

// Open a specific media item using ParcelFileDescriptor. val resolver = applicationContext.contentResolver // "rw" for read-and-write. // "rwt" for truncating or overwriting existing file contents. val readOnlyMode = "r" resolver.openFileDescriptor(content-uri, readOnlyMode).use { pfd ->

// Perform operations on "pfd".
}

8 nhưng không có các quyền cần thiết, thì

// Open a specific media item using ParcelFileDescriptor. ContentResolver resolver = getApplicationContext()

    .getContentResolver();
// "rw" for read-and-write. // "rwt" for truncating or overwriting existing file contents. String readOnlyMode = "r"; try (ParcelFileDescriptor pfd =
    resolver.openFileDescriptor(content-uri, readOnlyMode)) {
// Perform operations on "pfd".
} catch (IOException e) {
e.printStackTrace();
}

2 sẽ xảy ra.

Để truy cập vào các tệp khác trong bộ nhớ dùng chung trên thiết bị chạy Android 10 (API cấp 29), bạn nên bằng cách đặt vào

// Open a specific media item using ParcelFileDescriptor. ContentResolver resolver = getApplicationContext()

    .getContentResolver();
// "rw" for read-and-write. // "rwt" for truncating or overwriting existing file contents. String readOnlyMode = "r"; try (ParcelFileDescriptor pfd =
    resolver.openFileDescriptor(content-uri, readOnlyMode)) {
// Perform operations on "pfd".
} catch (IOException e) {
e.printStackTrace();
}

4 trong tệp kê khai của ứng dụng. Để truy cập vào các tệp nội dung nghe nhìn bằng các phương thức tệp gốc trên Android 10, bạn cũng phải yêu cầu cấp quyền .

Những yếu tố nên cân nhắc khi truy cập vào nội dung nghe nhìn

Khi truy cập vào nội dung phương tiện, hãy lưu ý những yếu tố nên cân nhắc được thảo luận trong các phần sau đây.

Dữ liệu đã lưu vào bộ nhớ đệm

Nếu ứng dụng của bạn lưu các URI hoặc dữ liệu từ kho nội dung nghe nhìn vào bộ nhớ đệm, hãy theo định kỳ. Bước kiểm tra này giúp dữ liệu đã lưu vào bộ nhớ đệm phía ứng dụng luôn được đồng bộ hoá với dữ liệu của nhà cung cấp phía hệ thống.

Hiệu suất

Khi thực hiện đọc tuần tự các tệp phương tiện bằng cách sử dụng đường dẫn tệp trực tiếp, hiệu suất tương đương với hiệu suất của API

// Load thumbnail of a specific media item. val thumbnail: Bitmap =

    applicationContext.contentResolver.loadThumbnail(
    content-uri, Size(640, 480), null)
7.

Tuy nhiên, khi bạn thực hiện đọc và ghi ngẫu nhiên các tệp phương tiện bằng đường dẫn tệp trực tiếp, quá trình này có thể kéo dài gấp đôi thời gian. Trong những trường hợp này, bạn nên sử dụng API

// Load thumbnail of a specific media item. val thumbnail: Bitmap =

    applicationContext.contentResolver.loadThumbnail(
    content-uri, Size(640, 480), null)
7.

Cột DATA (DỮ LIỆU)

Khi truy cập vào một tệp phương tiện hiện có, bạn có thể sử dụng giá trị của cột trong logic của mình. Đó là vì giá trị này có một đường dẫn tệp hợp lệ. Tuy nhiên, đừng cho rằng tệp luôn có sẵn. Hãy chuẩn bị để sẵn sàng xử lý mọi lỗi I/O dựa trên tệp xảy ra.

Mặt khác, để tạo hoặc cập nhật một tệp nội dung nghe nhìn, không sử dụng giá trị của cột

// Open a specific media item using ParcelFileDescriptor. ContentResolver resolver = getApplicationContext()

    .getContentResolver();
// "rw" for read-and-write. // "rwt" for truncating or overwriting existing file contents. String readOnlyMode = "r"; try (ParcelFileDescriptor pfd =
    resolver.openFileDescriptor(content-uri, readOnlyMode)) {
// Perform operations on "pfd".
} catch (IOException e) {
e.printStackTrace();
}

8. Thay vào đó, hãy sử dụng các giá trị của cột và .

Phương tiện bộ nhớ

Các ứng dụng nhắm mục tiêu đến Android 10 trở lên có thể truy cập vào tên riêng biệt mà hệ thống chỉ định cho từng phương tiện bộ nhớ ngoài. Hệ thống đặt tên này giúp bạn sắp xếp và lập chỉ mục nội dung một cách hiệu quả, đồng thời giúp bạn kiểm soát nơi lưu trữ các tệp phương tiện mới.

Các phương tiện nhớ sau đây đặc biệt hữu ích và cần ghi nhớ:

  • Phương tiện nhớ cung cấp chế độ xem toàn bộ phương tiện bộ nhớ dùng chung trên thiết bị. Bạn có thể đọc nội dung của phương tiện nhớ tổng hợp này, nhưng không thể sửa đổi nội dung.
  • Phương tiện nhớ thể hiện phương tiện bộ nhớ dùng chung chính trên thiết bị. Bạn có thể đọc và sửa đổi nội dung của phương tiện nhớ này.

Bạn có thể khám phá các phương tiện nhớ khác bằng cách gọi :

Kotlin

String[] projection = new String[] {

    media-database-columns-to-retrieve
}; String selection = sql-where-clause-with-placeholder-variables; String[] selectionArgs = new String[] {
    values-of-placeholder-variables
}; String sortOrder = sql-order-by-clause; Cursor cursor = getApplicationContext().getContentResolver().query(
MediaStore.media-type.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
); while (cursor.moveToNext()) {
// Use an ID column from the projection to get
// a URI representing the media item itself.
}

1

Java

String[] projection = new String[] {

    media-database-columns-to-retrieve
}; String selection = sql-where-clause-with-placeholder-variables; String[] selectionArgs = new String[] {
    values-of-placeholder-variables
}; String sortOrder = sql-order-by-clause; Cursor cursor = getApplicationContext().getContentResolver().query(
MediaStore.media-type.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
); while (cursor.moveToNext()) {
// Use an ID column from the projection to get
// a URI representing the media item itself.
}

2

Vị trí đã ghi lại nội dung phương tiện

Một số ảnh chụp và video có chứa thông tin vị trí trong siêu dữ liệu, cho biết địa điểm chụp ảnh hoặc địa điểm quay video.

Cách bạn truy cập vào thông tin vị trí này trong ứng dụng phụ thuộc vào việc bạn cần truy cập vào thông tin vị trí của ảnh chụp hay video.

Ảnh chụp

Nếu ứng dụng của bạn sử dụng , thì hệ thống sẽ ẩn thông tin vị trí theo mặc định. Để truy cập vào thông tin này, hãy hoàn tất các bước sau đây:

  1. Yêu cầu quyền trong tệp kê khai của ứng dụng.
  2. Từ đối tượng

    // Load thumbnail of a specific media item. val thumbnail: Bitmap =

        applicationContext.contentResolver.loadThumbnail(  
        content-uri, Size(640, 480), null)  
    
    7 của bạn, hãy lấy lượng byte chính xác của ảnh chụp bằng cách gọi rồi chuyển vào đó URI của ảnh chụp, như minh hoạ trong đoạn mã sau đây:

    Kotlin

    String[] projection = new String[] {

        media-database-columns-to-retrieve  
    
    }; String selection = sql-where-clause-with-placeholder-variables; String[] selectionArgs = new String[] {
        values-of-placeholder-variables  
    
    }; String sortOrder = sql-order-by-clause; Cursor cursor = getApplicationContext().getContentResolver().query(
    MediaStore.media-type.Media.EXTERNAL_CONTENT_URI,  
    projection,  
    selection,  
    selectionArgs,  
    sortOrder  
    
    ); while (cursor.moveToNext()) {
    // Use an ID column from the projection to get  
    // a URI representing the media item itself.  
    
    } 3

    Java

    String[] projection = new String[] {
        media-database-columns-to-retrieve  
    
    }; String selection = sql-where-clause-with-placeholder-variables; String[] selectionArgs = new String[] {
        values-of-placeholder-variables  
    
    }; String sortOrder = sql-order-by-clause; Cursor cursor = getApplicationContext().getContentResolver().query(
    MediaStore.media-type.Media.EXTERNAL_CONTENT_URI,  
    projection,  
    selection,  
    selectionArgs,  
    sortOrder  
    
    ); while (cursor.moveToNext()) {
    // Use an ID column from the projection to get  
    // a URI representing the media item itself.  
    
    } 4

Video

Để truy cập vào thông tin vị trí trong siêu dữ liệu của một video, hãy sử dụng lớp

// Open a specific media item using InputStream. val resolver = applicationContext.contentResolver resolver.openInputStream(content-uri).use { stream ->

// Perform operations on "stream".
}

8 như trong đoạn mã sau đây. Ứng dụng của bạn không cần yêu cầu cấp thêm bất kỳ quyền nào để sử dụng lớp này.

Kotlin

String[] projection = new String[] {

    media-database-columns-to-retrieve
}; String selection = sql-where-clause-with-placeholder-variables; String[] selectionArgs = new String[] {
    values-of-placeholder-variables
}; String sortOrder = sql-order-by-clause; Cursor cursor = getApplicationContext().getContentResolver().query(
MediaStore.media-type.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
); while (cursor.moveToNext()) {
// Use an ID column from the projection to get
// a URI representing the media item itself.
}

5

Java

String[] projection = new String[] {

    media-database-columns-to-retrieve
}; String selection = sql-where-clause-with-placeholder-variables; String[] selectionArgs = new String[] {
    values-of-placeholder-variables
}; String sortOrder = sql-order-by-clause; Cursor cursor = getApplicationContext().getContentResolver().query(
MediaStore.media-type.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
); while (cursor.moveToNext()) {
// Use an ID column from the projection to get
// a URI representing the media item itself.
}

6

Một số ứng dụng cho phép người dùng chia sẻ tệp nội dung nghe nhìn với nhau. Ví dụ: ứng dụng mạng xã hội cho phép người dùng chia sẻ ảnh và video với bạn bè.

Để chia sẻ các tệp nội dung nghe nhìn, hãy sử dụng URI

// Open a specific media item using InputStream. val resolver = applicationContext.contentResolver resolver.openInputStream(content-uri).use { stream ->

// Perform operations on "stream".
}

9, như đề xuất trong hướng dẫn tạo một nhà cung cấp nội dung.

Phân bổ các tệp phương tiện cho ứng dụng

Khi bạn bật cho một ứng dụng nhắm mục tiêu đến Android 10 trở lên, hệ thống phân bổ ứng dụng vào từng tệp phương tiện, xác định các tệp mà ứng dụng của bạn có thể truy cập khi chưa yêu cầu cấp bất kỳ quyền truy cập vào bộ nhớ nào. Mỗi tệp chỉ có thể được phân bổ cho một ứng dụng. Do đó, nếu ứng dụng của bạn tạo một tệp phương tiện được lưu trữ trong bộ sưu tập phương tiện ảnh, video hoặc tệp âm thanh, thì ứng dụng sẽ có quyền truy cập vào tệp đó.

Tuy nhiên, nếu người dùng gỡ cài đặt rồi cài đặt lại ứng dụng của bạn, thì bạn phải yêu cầu để truy cập vào các tệp mà ứng dụng của bạn đã tạo ban đầu. Yêu cầu cấp quyền này là bắt buộc vì hệ thống xem xét tệp được phân bổ cho phiên bản đã cài đặt trước đó của ứng dụng, thay vì phiên bản mới cài đặt.

Thêm một mục

Để thêm một mục nội dung nghe nhìn vào bộ sưu tập hiện có, hãy dùng mã tương tự như sau. Đoạn mã này truy cập phương tiện

// Open a specific media item using InputStream. val resolver = applicationContext.contentResolver resolver.openInputStream(content-uri).use { stream ->

// Perform operations on "stream".
}

3 trên các thiết bị chạy Android 10 trở lên. Lý do là vì trên các thiết bị này, bạn chỉ có thể sửa đổi nội dung của một phương tiện nếu đó là phương tiện chính, như mô tả trong phần .

Kotlin

String[] projection = new String[] {

    media-database-columns-to-retrieve
}; String selection = sql-where-clause-with-placeholder-variables; String[] selectionArgs = new String[] {
    values-of-placeholder-variables
}; String sortOrder = sql-order-by-clause; Cursor cursor = getApplicationContext().getContentResolver().query(
MediaStore.media-type.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
); while (cursor.moveToNext()) {
// Use an ID column from the projection to get
// a URI representing the media item itself.
}

7

Java

String[] projection = new String[] {

    media-database-columns-to-retrieve
}; String selection = sql-where-clause-with-placeholder-variables; String[] selectionArgs = new String[] {
    values-of-placeholder-variables
}; String sortOrder = sql-order-by-clause; Cursor cursor = getApplicationContext().getContentResolver().query(
MediaStore.media-type.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
); while (cursor.moveToNext()) {
// Use an ID column from the projection to get
// a URI representing the media item itself.
}

8

Chuyển đổi trạng thái đang chờ xử lý cho các tệp phương tiện

Nếu ứng dụng của bạn thực hiện các thao tác có thể tốn nhiều thời gian, chẳng hạn như ghi vào các tệp nội dung nghe nhìn, thì bạn nên có quyền truy cập độc quyền vào tệp khi tệp đang được xử lý. Trên các thiết bị chạy Android 10 trở lên, ứng dụng của bạn có thể lấy quyền truy cập độc quyền này bằng cách đặt giá trị của cờ thành 1. Chỉ ứng dụng của bạn mới có thể xem tệp cho đến khi ứng dụng thay đổi giá trị của

String[] projection = new String[] {

    media-database-columns-to-retrieve
}; String selection = sql-where-clause-with-placeholder-variables; String[] selectionArgs = new String[] {
    values-of-placeholder-variables
}; String sortOrder = sql-order-by-clause; Cursor cursor = getApplicationContext().getContentResolver().query(
MediaStore.media-type.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
); while (cursor.moveToNext()) {
// Use an ID column from the projection to get
// a URI representing the media item itself.
}

02 về 0.

Đoạn mã sau đó dựa trên đoạn mã trước đó. Đoạn mã này cho biết cách sử dụng cờ

String[] projection = new String[] {

    media-database-columns-to-retrieve
}; String selection = sql-where-clause-with-placeholder-variables; String[] selectionArgs = new String[] {
    values-of-placeholder-variables
}; String sortOrder = sql-order-by-clause; Cursor cursor = getApplicationContext().getContentResolver().query(
MediaStore.media-type.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
); while (cursor.moveToNext()) {
// Use an ID column from the projection to get
// a URI representing the media item itself.
}

02 khi lưu trữ một bài hát dài trong thư mục tương ứng với bộ sưu tập

// Load thumbnail of a specific media item. val thumbnail: Bitmap =

    applicationContext.contentResolver.loadThumbnail(
    content-uri, Size(640, 480), null)
0:

Kotlin

String[] projection = new String[] {

    media-database-columns-to-retrieve
}; String selection = sql-where-clause-with-placeholder-variables; String[] selectionArgs = new String[] {
    values-of-placeholder-variables
}; String sortOrder = sql-order-by-clause; Cursor cursor = getApplicationContext().getContentResolver().query(
MediaStore.media-type.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
); while (cursor.moveToNext()) {
// Use an ID column from the projection to get
// a URI representing the media item itself.
}

9

Java

<! Required only if your app needs to access images or photos

 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <! Required only if your app needs to access videos
 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <!-- Required only if your app needs to access audio files
 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
             android:maxSdkVersion="29" />
0

Gợi ý về vị trí tệp

Khi ứng dụng của bạn lưu trữ nội dung nghe nhìn trên một thiết bị chạy Android 10, nội dung nghe nhìn được sắp xếp dựa trên loại nội dung nghe nhìn theo mặc định. Ví dụ: theo mặc định, các tệp hình ảnh mới sẽ được đặt trong thư mục , tương ứng với bộ sưu tập

// Need the READ_EXTERNAL_STORAGE permission if accessing video files that your // app didn't create. // Container for information about each video. data class Video(val uri: Uri,

val name: String,
val duration: Int,
val size: Int
) val videoList = mutableListOf<Video>() 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
) // Show only videos that are at least 5 minutes in duration. val selection = "${MediaStore.Video.Media.DURATION} >= ?" val selectionArgs = arrayOf(
TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES).toString()
) // Display videos in alphabetical order based on their display name. val sortOrder = "${MediaStore.Video.Media.DISPLAY_NAME} ASC" val query = 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)
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 contentUri: Uri = ContentUris.withAppendedId(
        MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
        id
    )
    // Stores column values and the contentUri in a local object
    // that represents the media file.
    videoList += Video(contentUri, name, duration, size)
}
}

6.

Nếu ứng dụng của bạn biết một vị trí cụ thể có thể lưu trữ các tệp, chẳng hạn như album ảnh có tên là

String[] projection = new String[] {

    media-database-columns-to-retrieve
}; String selection = sql-where-clause-with-placeholder-variables; String[] selectionArgs = new String[] {
    values-of-placeholder-variables
}; String sortOrder = sql-order-by-clause; Cursor cursor = getApplicationContext().getContentResolver().query(
MediaStore.media-type.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
); while (cursor.moveToNext()) {
// Use an ID column from the projection to get
// a URI representing the media item itself.
}

08, bạn có thể đặt để cung cấp cho hệ thống gợi ý về vị trí lưu trữ các tệp mới ghi.

Cập nhật một mục

Để cập nhật tệp nội dung nghe nhìn mà ứng dụng của bạn sở hữu, hãy dùng mã tương tự như sau:

Kotlin

<! Required only if your app needs to access images or photos

 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <! Required only if your app needs to access videos
 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <!-- Required only if your app needs to access audio files
 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
             android:maxSdkVersion="29" />
1

Java

<! Required only if your app needs to access images or photos

 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <! Required only if your app needs to access videos
 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <!-- Required only if your app needs to access audio files
 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
             android:maxSdkVersion="29" />
2

Nếu bộ nhớ có giới hạn không có sẵn hoặc không được bật, quá trình được thể hiện trong đoạn mã trước đó cũng sẽ hoạt động cho các tệp mà ứng dụng của bạn không sở hữu.

Cập nhật trong mã gốc

Nếu bạn cần ghi tệp phương tiện bằng thư viện gốc, hãy truyền chỉ số mô tả tệp liên kết của tệp từ mã dựa trên Java hoặc dựa trên Kotlin vào mã gốc của bạn.

Đoạn mã sau đây cho biết cách truyền chỉ số mô tả tệp của đối tượng nội dung phương tiện vào mã gốc của ứng dụng:

Kotlin

<! Required only if your app needs to access images or photos

 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <! Required only if your app needs to access videos
 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <!-- Required only if your app needs to access audio files
 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
             android:maxSdkVersion="29" />
3

Java

<! Required only if your app needs to access images or photos

 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <! Required only if your app needs to access videos
 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <!-- Required only if your app needs to access audio files
 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
             android:maxSdkVersion="29" />
4

Cập nhật tệp nội dung nghe nhìn của các ứng dụng khác

Nếu ứng dụng của bạn sử dụng , thì thường không thể cập nhật tệp nội dung nghe nhìn mà một ứng dụng khác đã đóng góp cho kho nội dung nghe nhìn.

Tuy nhiên, bạn vẫn có thể xin người dùng đồng ý cho sửa đổi tệp bằng cách bắt (catch)

String[] projection = new String[] {

    media-database-columns-to-retrieve
}; String selection = sql-where-clause-with-placeholder-variables; String[] selectionArgs = new String[] {
    values-of-placeholder-variables
}; String sortOrder = sql-order-by-clause; Cursor cursor = getApplicationContext().getContentResolver().query(
MediaStore.media-type.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
); while (cursor.moveToNext()) {
// Use an ID column from the projection to get
// a URI representing the media item itself.
}

10 mà nền tảng đưa ra (throw). Khi đó, bạn có thể yêu cầu người dùng cấp cho ứng dụng của bạn quyền ghi vào mục cụ thể đó, như minh hoạ trong đoạn mã sau:

Kotlin

<! Required only if your app needs to access images or photos

 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <! Required only if your app needs to access videos
 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <!-- Required only if your app needs to access audio files
 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
             android:maxSdkVersion="29" />
5

Java

<! Required only if your app needs to access images or photos

 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <! Required only if your app needs to access videos
 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <!-- Required only if your app needs to access audio files
 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
             android:maxSdkVersion="29" />
6

Hoàn tất quá trình này mỗi khi ứng dụng của bạn cần sửa đổi một tệp nội dung nghe nhìn mà ứng dụng không tạo.

Ngoài ra, nếu ứng dụng của bạn chạy trên Android 11 trở lên, bạn có thể cho phép người dùng cấp cho ứng dụng quyền ghi vào một nhóm tệp nội dung nghe nhìn. Sử dụng phương thức , như mô tả trong phần về cách .

Nếu ứng dụng của bạn có một trường hợp sử dụng khác không được bộ nhớ có giới hạn hỗ trợ, hãy gửi một yêu cầu về tính năng và .

Xoá một mục

Để xoá một mục mà ứng dụng của bạn không còn cần đến trong kho phương tiện, hãy sử dụng logic tương tự như trong đoạn mã sau:

Kotlin

<! Required only if your app needs to access images or photos

 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <! Required only if your app needs to access videos
 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <!-- Required only if your app needs to access audio files
 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
             android:maxSdkVersion="29" />
7

Java

<! Required only if your app needs to access images or photos

 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <! Required only if your app needs to access videos
 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <!-- Required only if your app needs to access audio files
 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
             android:maxSdkVersion="29" />
8

Nếu bộ nhớ có giới hạn không có sẵn hoặc không được bật, bạn có thể sử dụng đoạn mã trước đó để xoá các tệp mà các ứng dụng khác sở hữu. Tuy nhiên, nếu bật bộ nhớ có giới hạn, bạn vẫn cần bắt

String[] projection = new String[] {

    media-database-columns-to-retrieve
}; String selection = sql-where-clause-with-placeholder-variables; String[] selectionArgs = new String[] {
    values-of-placeholder-variables
}; String sortOrder = sql-order-by-clause; Cursor cursor = getApplicationContext().getContentResolver().query(
MediaStore.media-type.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
); while (cursor.moveToNext()) {
// Use an ID column from the projection to get
// a URI representing the media item itself.
}

10 cho mỗi tệp mà ứng dụng của bạn muốn xoá, như mô tả trong phần về cách .

Nếu ứng dụng của bạn chạy trên Android 11 trở lên, bạn có thể cho phép người dùng chọn một nhóm tệp nội dung nghe nhìn cần xoá. Sử dụng phương thức hoặc phương thức , như mô tả trong phần về cách .

Nếu ứng dụng của bạn có một trường hợp sử dụng khác không được bộ nhớ có giới hạn hỗ trợ, hãy gửi một yêu cầu về tính năng và .

Ứng dụng của bạn có thể cần xác định những phương tiện bộ nhớ chứa các tệp phương tiện mà các ứng dụng đã thêm hoặc sửa đổi, so với thời điểm trước đó. Để phát hiện những thay đổi này sao cho đáng tin cậy nhất, hãy chuyển phương tiện bộ nhớ liên quan vào . Miễn là phiên bản kho phương tiện không thay đổi, thì giá trị trả về của phương thức này sẽ tăng đơn điệu theo thời gian.

Cụ thể,

String[] projection = new String[] {

    media-database-columns-to-retrieve
}; String selection = sql-where-clause-with-placeholder-variables; String[] selectionArgs = new String[] {
    values-of-placeholder-variables
}; String sortOrder = sql-order-by-clause; Cursor cursor = getApplicationContext().getContentResolver().query(
MediaStore.media-type.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
); while (cursor.moveToNext()) {
// Use an ID column from the projection to get
// a URI representing the media item itself.
}

15 sẽ có hiệu quả cao hơn so với ngày trong các cột nội dung nghe nhìn, chẳng hạn như và . Đó là vì các giá trị cột nội dung nghe nhìn đó có thể thay đổi khi một ứng dụng gọi hoặc khi người dùng thay đổi đồng hồ hệ thống.

Quản lý các nhóm tệp phương tiện

Trên Android 11 trở lên, bạn có thể yêu cầu người dùng chọn một nhóm tệp phương tiện, sau đó cập nhật các tệp phương tiện này trong một thao tác. Các phương thức này cho tính nhất quán tốt hơn giữa các thiết bị và giúp người dùng quản lý các bộ sưu tập phương tiện của họ dễ dàng hơn.

Các phương thức cung cấp chức năng "cập nhật theo lô" này bao gồm:

Yêu cầu người dùng cấp cho ứng dụng của bạn quyền ghi vào nhóm tệp nội dung nghe nhìn đã chỉ định. Yêu cầu người dùng đánh dấu các tệp nội dung nghe nhìn đã chỉ định là một số nội dung nghe nhìn "yêu thích" trên thiết bị. Bất kỳ ứng dụng nào có quyền đọc tệp này đều có thể thấy rằng người dùng đã đánh dấu tệp là "yêu thích".

Yêu cầu người dùng cho các tệp nội dung nghe nhìn đã chỉ định vào thùng rác của thiết bị. Các mục trong thùng rác sẽ bị xoá vĩnh viễn sau một khoảng thời gian do hệ thống xác định.

Yêu cầu người dùng xoá vĩnh viễn ngay các tệp phương tiện đã chỉ định mà không cần cho vào thùng rác trước.

Sau khi gọi bất kỳ phương thức nào trong số này, hệ thống sẽ tạo một đối tượng

String[] projection = new String[] {

    media-database-columns-to-retrieve
}; String selection = sql-where-clause-with-placeholder-variables; String[] selectionArgs = new String[] {
    values-of-placeholder-variables
}; String sortOrder = sql-order-by-clause; Cursor cursor = getApplicationContext().getContentResolver().query(
MediaStore.media-type.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
); while (cursor.moveToNext()) {
// Use an ID column from the projection to get
// a URI representing the media item itself.
}

24. Sau khi ứng dụng của bạn gọi ra ý định này, người dùng sẽ thấy hộp thoại yêu cầu họ đồng ý cho ứng dụng của bạn cập nhật hoặc xoá các tệp phương tiện đã chỉ định.

Ví dụ về cách định cấu trúc lệnh gọi tới

String[] projection = new String[] {

    media-database-columns-to-retrieve
}; String selection = sql-where-clause-with-placeholder-variables; String[] selectionArgs = new String[] {
    values-of-placeholder-variables
}; String sortOrder = sql-order-by-clause; Cursor cursor = getApplicationContext().getContentResolver().query(
MediaStore.media-type.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
); while (cursor.moveToNext()) {
// Use an ID column from the projection to get
// a URI representing the media item itself.
}

11:

Kotlin

<! Required only if your app needs to access images or photos

 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <! Required only if your app needs to access videos
 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <!-- Required only if your app needs to access audio files
 that other apps created. -->
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
             android:maxSdkVersion="29" />
9

Java

// Need the READ_EXTERNAL_STORAGE permission if accessing video files that your // app didn't create. // Container for information about each video. data class Video(val uri: Uri,

val name: String,
val duration: Int,
val size: Int
) val videoList = mutableListOf<Video>() 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
) // Show only videos that are at least 5 minutes in duration. val selection = "${MediaStore.Video.Media.DURATION} >= ?" val selectionArgs = arrayOf(
TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES).toString()
) // Display videos in alphabetical order based on their display name. val sortOrder = "${MediaStore.Video.Media.DISPLAY_NAME} ASC" val query = 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)
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 contentUri: Uri = ContentUris.withAppendedId(
        MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
        id
    )
    // Stores column values and the contentUri in a local object
    // that represents the media file.
    videoList += Video(contentUri, name, duration, size)
}
}

0

Đánh giá phản hồi của người dùng. Nếu người dùng đã đồng ý, hãy tiến hành thao tác với nội dung phương tiện. Nếu không, hãy giải thích cho người dùng biết lý do ứng dụng của bạn cần được cấp quyền:

Kotlin

// Need the READ_EXTERNAL_STORAGE permission if accessing video files that your // app didn't create. // Container for information about each video. data class Video(val uri: Uri,

val name: String,
val duration: Int,
val size: Int
) val videoList = mutableListOf<Video>() 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
) // Show only videos that are at least 5 minutes in duration. val selection = "${MediaStore.Video.Media.DURATION} >= ?" val selectionArgs = arrayOf(
TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES).toString()
) // Display videos in alphabetical order based on their display name. val sortOrder = "${MediaStore.Video.Media.DISPLAY_NAME} ASC" val query = 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)
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 contentUri: Uri = ContentUris.withAppendedId(
        MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
        id
    )
    // Stores column values and the contentUri in a local object
    // that represents the media file.
    videoList += Video(contentUri, name, duration, size)
}
}

1

Java

// Need the READ_EXTERNAL_STORAGE permission if accessing video files that your // app didn't create. // Container for information about each video. data class Video(val uri: Uri,

val name: String,
val duration: Int,
val size: Int
) val videoList = mutableListOf<Video>() 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
) // Show only videos that are at least 5 minutes in duration. val selection = "${MediaStore.Video.Media.DURATION} >= ?" val selectionArgs = arrayOf(
TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES).toString()
) // Display videos in alphabetical order based on their display name. val sortOrder = "${MediaStore.Video.Media.DISPLAY_NAME} ASC" val query = 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)
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 contentUri: Uri = ContentUris.withAppendedId(
        MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
        id
    )
    // Stores column values and the contentUri in a local object
    // that represents the media file.
    videoList += Video(contentUri, name, duration, size)
}
}

2

Bạn có thể sử dụng cùng một mẫu chung này với , , và .

Quyền quản lý nội dung phương tiện

Người dùng có thể tin tưởng cho một ứng dụng cụ thể phụ trách quản lý nội dung phương tiện, chẳng hạn như chỉnh sửa thường xuyên các tệp phương tiện. Nếu ứng dụng của bạn nhắm mục tiêu đến Android 11 trở lên và không phải là ứng dụng thư viện mặc định của thiết bị, bạn phải hiển thị hộp thoại xác nhận cho người dùng mỗi khi ứng dụng cố gắng sửa đổi hoặc xoá tệp.

Nếu ứng dụng của bạn nhắm mục tiêu đến Android 12 (API cấp 31) trở lên, thì bạn có thể yêu cầu người dùng cấp cho ứng dụng của bạn quyền đặc biệt là quản lý nội dung nghe nhìn. Quyền này cho phép ứng dụng của bạn thực hiện từng thao tác sau trên tệp mà không cần nhắc người dùng:

  • Sửa đổi tệp, bằng cách sử dụng .
  • Chuyển tệp vào và ra khỏi thùng rác, bằng cách sử dụng .
  • Xoá tệp, bằng cách sử dụng .

Để làm được điều này, vui lòng hoàn thành các bước sau:

  1. Khai báo quyền và quyền trong tệp kê khai của ứng dụng. Để gọi String[] projection = new String[] {
        media-database-columns-to-retrieve  
    
    }; String selection = sql-where-clause-with-placeholder-variables; String[] selectionArgs = new String[] {
        values-of-placeholder-variables  
    
    }; String sortOrder = sql-order-by-clause; Cursor cursor = getApplicationContext().getContentResolver().query(
    MediaStore.media-type.Media.EXTERNAL_CONTENT_URI,  
    projection,  
    selection,  
    selectionArgs,  
    sortOrder  
    
    ); while (cursor.moveToNext()) {
    // Use an ID column from the projection to get  
    // a URI representing the media item itself.  
    
    } 11 mà không hiển thị hộp thoại xác nhận, bạn cũng cần khai báo quyền .
  2. Trong ứng dụng của bạn, hãy hiển thị một giao diện cho người dùng để giải thích lý do họ nên cấp quyền quản lý nội dung nghe nhìn cho ứng dụng của bạn.
  3. Gọi thao tác theo ý định . Thao tác này sẽ đưa người dùng đến màn hình Media management apps (Ứng dụng quản lý nội dung phương tiện) trong phần cài đặt hệ thống. Từ đây, người dùng có thể cấp quyền truy cập đặc biệt cho ứng dụng.

Các trường hợp sử dụng yêu cầu phương án thay thế cho kho phương tiện

Nếu ứng dụng của bạn chủ yếu thực hiện một trong các vai trò sau đây, hãy cân nhắc phương án thay thế cho các API

// Load thumbnail of a specific media item. val thumbnail: Bitmap =

    applicationContext.contentResolver.loadThumbnail(
    content-uri, Size(640, 480), null)
7.

Làm việc với các loại tệp khác

Nếu ứng dụng của bạn làm việc với các tài liệu và tệp không chỉ chứa nội dung nghe nhìn, chẳng hạn như các tệp có đuôi EPUB hoặc PDF, hãy sử dụng thao tác theo ý định

String[] projection = new String[] {

    media-database-columns-to-retrieve
}; String selection = sql-where-clause-with-placeholder-variables; String[] selectionArgs = new String[] {
    values-of-placeholder-variables
}; String sortOrder = sql-order-by-clause; Cursor cursor = getApplicationContext().getContentResolver().query(
MediaStore.media-type.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
); while (cursor.moveToNext()) {
// Use an ID column from the projection to get
// a URI representing the media item itself.
}

38, như mô tả trong phần hướng dẫn về cách lưu trữ và truy cập vào tài liệu cũng như các tệp khác.

Tính năng chia sẻ tệp trong các ứng dụng đồng hành

Trong trường hợp bạn cung cấp một bộ ứng dụng đồng hành – chẳng hạn như ứng dụng nhắn tin và ứng dụng hồ sơ – hãy thiết lập tính năng chia sẻ tệp bằng cách sử dụng các URI

// Open a specific media item using InputStream. val resolver = applicationContext.contentResolver resolver.openInputStream(content-uri).use { stream ->

// Perform operations on "stream".
}

9. Quy trình công việc này cũng là .

Tài nguyên khác

Để biết thêm thông tin về cách lưu trữ và truy cập nội dung phương tiện, hãy tham khảo các tài nguyên sau.