Content Providers

Content providers with content resolver

A content provider is a component of the Android operating system that provides data to other apps. It stores and retrieves data from a database and makes it available to other apps on the device. Content providers are a key part of Android's data-sharing architecture, as they allow apps to share data and access data from external sources.

For example, the Android contacts app uses a content provider to make the device's contact information available to other apps, such as the dialer app. Content providers are typically used for sharing data that is either private to the app or that needs to be shared with other apps on the device.

General Steps for Using a ContentProvider

You will take the following steps:

  1. Get permission to use the ContentProvider.

  2. Get the ContentResolver

  3. Pick one of four basic actions on the data: query, insert, update, delete

1: Get permission to use the ContentProvider

In this case, we are going to query media from the device.

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    tools:ignore="ScopedStorage" />

// for api level 33+
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>

2: Get the ContentResolver

The Android content resolver is a system-level service that manages access to data stored in various content providers on the device. Content providers are used to sharing data between different applications, and the content resolver provides a unified interface for accessing data from different content providers.

  • get content resolver
val contentResolver = context.contentResolver

3: Four basic operations

// Query the content provider
val cursor = contentResolver.query(uri, projection, selection, selectionArgs, sortOrder)

// Insert a new record into the content provider
val uri = contentResolver.insert(uri, values)

// Update an existing record in the content provider
val rowsUpdated = contentResolver.update(uri, values, selection, selectionArgs)

// Delete a record from the content provider
val rowsDeleted = contentResolver.delete(uri, selection, selectionArgs)
  • URI (Uniform Resource Identifier)

URI (Uniform Resource Identifier) is a string that identifies a specific data resource, such as a content provider or a file. URIs are used to reference data in Android applications, and they can be used in various ways, such as to specify the location of a file, to identify a content provider, or to perform operations on the data stored in a content provider.

URLs are subsets of URI that are specifically meant to identify network locations. Such as websites and files on the website.

There are different types of URIs in Android, including content URIs, file URIs, and hierarchical URIs. A content URI is used to reference data in a content provider, and it typically has the following format:

content://<authority>/<path>

where <authority> is the unique identifier of the content provider and <path> specifies the location of the data within the content provider.

A file URI is used to reference a file on the device, and it typically has the following format:

file://<path>

where <path> specifies the location of the file on the device.

A hierarchical URI is a general-purpose URI that can be used to reference any type of data on the device, and it typically has the following format:

<scheme>:<path>

where <scheme> specifies the type of data being referenced and <path> specifies the location of the data within the specified scheme.

In Android, URIs are used in various ways, such as to specify the location of a file that should be opened, to identify a content provider that should be queried or updated, or to specify the location of a file that should be shared with another application. They provide a flexible and powerful way to access and manipulate data in Android applications. To get media, we need to use the media content provider URIs.

val imagesUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val videosUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
val audioUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
val externalFilesUri = MediaStore.Files.getContentUri("external")
  • Query the content provider

The query method returns a cursor. The cursor is a data structure that is used to read and manipulate the data returned by a content provider. It acts like an iterator, allowing you to move through the data one record at a time, and access the values of each field.

val cursor = contentResolver.query(imagesUri,
 <projection>, <selection>, <selection args>, <sort order>)

Getting images using the cursor


fun getImages(
    context: Context, 
    imageList: ArrayList<Media>, 
    adapter: MediaAdapter) 
= viewModelScope.launch {
    // 1: get the content resolver
    val contentResolver = context.contentResolver

    // 2: get the content provider URI
    val imagesUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI

    // 3: query data. It method returns a cursor.
    val cursor : Cursor? = contentResolver.query(
        imagesUri,
        null, null, null, null
    )
    // cursor acts like an iterator, allowing you to move through the data one record at a time
    if (cursor != null) {
        val count = cursor.count
        // get the column index
        val imageId = cursor.getColumnIndex(MediaStore.Images.Media._ID)
        if (count > 0) {
            for (i in 0 until count) {
                cursor.moveToPosition(i)
                // get the item/row in that column
                val getImageId = cursor.getLong(imageId)
                val imageContentUri = ContentUris.withAppendedId(imagesUri, getImageId)
                val media = Media(getImageId, imageContentUri)
                imageList.add(media)
            }
            cursor.close()
            adapter.differ.submitList(imageList)
        }
    }
}