Content Provider: Component Architecture and Working Principle

Author: IT Sectr Published: 2026-06-17 Reading time: 8 min

Content Provider is an Android component that provides a unified interface for data access between applications. It abstracts physical storage (SQLite, files, network sources) and enables secure information exchange through ContentResolver. According to Android Developer Guide, 2026, Content Provider is one of the four main components of an Android application, alongside Activity, Service, and BroadcastReceiver. Its task is to make data available to other applications with read and write permission control.

Key Takeaways

  • Content Provider is a standard Android component for inter-application data exchange through the ContentResolver interface.
  • URI (content://) identifies a table or record and is used for all CRUD operations with the provider.
  • UriMatcher is a utility class that parses incoming URIs and determines which table or row is being requested.
  • Permissions for reading and writing are defined in the manifest and requested from the user during installation.
  • CursorLoader or Room with Content Provider enables asynchronous data loading from the provider without blocking the UI thread.

What Is Content Provider?

Content Provider is an Android component that manages access to a centralized data store and provides it to other applications through a unified contract interface. It hides storage implementation details: data can be stored in SQLite, on the file system, in the cloud, or be the result of a network request.

Android includes built-in Content Providers for system data — ContactsContract, MediaStore, CalendarContract, CallLog. Third-party applications can also create their own providers for secure data exchange. Each provider is registered in AndroidManifest.xml with an authority — a unique string that forms the first part of the URI.

How Content Provider Works

Content Provider operates on a client-server model. The provider acts as a server that implements six required methods: query, insert, update, delete, getType, and onCreate. The client (another application) accesses the provider through ContentResolver, which translates calls into the corresponding provider methods via Android's IPC mechanism.

URI and Authority

Each Content Provider is identified by a URI of the content:// scheme. For example, content://com.example.app.provider/items. The first part authority (com.example.app.provider) is bound to the provider class in the manifest. The path /items points to a table, while /items/5 points to a specific record with ID=5.

Call Process

When an application calls ContentResolver.query(URI), Android checks the calling package's permissions, finds the provider by authority, and starts its process if it is not already running. The provider executes the query and returns a Cursor — an object that contains the result and allows the client to iterate over records.

Core Content Provider Methods

The ContentProvider class requires implementing six abstract methods. Each method accepts a URI and returns a result corresponding to the operation type. The system calls these methods from any process, so they must be thread-safe and not block execution for a long time.

query Method

The query method accepts a URI, a projection array of columns, a selection string with arguments, and a sort order. It returns a Cursor with data. In the implementation, you need to parse the URI using UriMatcher and execute the corresponding SQL query against the database.

insert, update, delete Methods

These methods modify data in the store. insert receives ContentValues — key-value pairs — and returns the URI of the new record. update and delete accept a selection for filtering records and return the number of affected rows. After changing data, the provider must notify about this through ContentResolver.notifyChange.

MethodPurposeReturn
queryRetrieve data by URICursor or null
insertAdd a new recordURI of new record
updateUpdate existing recordsint (row count)
deleteDelete recordsint (row count)
getTypeMIME type for URIString
onCreateProvider initializationboolean

ContentResolver and URI in Android

ContentResolver is a single access point for working with all Content Providers in the system. The client application never calls provider methods directly — only through ContentResolver, which Android obtains from the context. CRUD operations in ContentResolver have the same names as in the provider but accept URIs instead of direct references.

UriMatcher

To parse incoming URIs inside the provider, UriMatcher is used. It allows mapping a URI to a numeric code — for example, URI content://authority/items yields code 1, and content://authority/items/# yields code 2. This eliminates the need for manual URI string parsing in each method.

kotlin
// Using ContentResolver to access contacts
val uri = ContactsContract.Contacts.CONTENT_URI
val cursor = contentResolver.query(
    uri,
    arrayOf(ContactsContract.Contacts.DISPLAY_NAME),
    null, null, null
)
cursor?.use {
    while (it.moveToNext()) {
        val name = it.getString(it.getColumnIndexOrThrow(
            ContactsContract.Contacts.DISPLAY_NAME
        ))
        Log.d("Contacts", "Name: $name")
    }
}

The Cursor must always be closed after use — in the example above, the use function (Kotlin extension) does this. If the Cursor is not closed, a memory leak occurs because it holds a reference to data in the Binder pool. For UI scenarios, use CursorLoader or Room with LiveData/Flow.

Content Provider Example in Kotlin

Creating your own Content Provider starts with extending the ContentProvider class. The provider works with an SQLite database through SQLiteOpenHelper and uses UriMatcher to determine the query type. Consider a minimal implementation for managing a list of notes.

Manifest Registration

The provider is registered in AndroidManifest.xml inside the application tag. The authorities attribute sets a unique identifier, and exported determines whether other applications can access the provider. Without exported=true, the provider is only accessible within your application.

kotlin
// Example Content Provider for notes
class NotesProvider : ContentProvider() {

    companion object {
        const val AUTHORITY = "com.example.app.notes"
        const val NOTES_PATH = "notes"
        const val NOTES_URI = "content://$AUTHORITY/$NOTES_PATH"
        const val NOTES_ID = "content://$AUTHORITY/$NOTES_PATH/#"

        private val uriMatcher = UriMatcher(UriMatcher.NO_MATCH).apply {
            addURI(AUTHORITY, NOTES_PATH, 1)
            addURI(AUTHORITY, "$NOTES_PATH/#", 2)
        }
    }

    override fun query(uri: Uri, projection: Array<String>?,
        selection: String?, args: Array<String>?, sort: String?): Cursor? {
        return when (uriMatcher.match(uri)) {
            1 -> dbHelper.readableDatabase.query(TABLE_NOTES,
                projection, selection, args, null, null, sort)
            2 -> dbHelper.readableDatabase.query(TABLE_NOTES,
                projection, "_id=?", arrayOf(uri.lastPathSegment), null, null, null)
            else -> throw IllegalArgumentException("Unknown URI: $uri")
        }
    }

    override fun insert(uri: Uri, values: ContentValues?): Uri? {
        val id = dbHelper.writableDatabase.insert(TABLE_NOTES, null, values)
        context?.contentResolver?.notifyChange(uri, null)
        return ContentUris.withAppendedId(uri, id)
    }

    override fun delete(uri: Uri, selection: String?, args: Array<String>?): Int {
        val count = dbHelper.writableDatabase.delete(TABLE_NOTES, selection, args)
        context?.contentResolver?.notifyChange(uri, null)
        return count
    }

    // getType, update, onCreate omitted for brevity
}

After creating the provider class, it must be registered in the manifest with the android:authorities and android:exported attributes (true if the provider is public). The system creates a provider instance upon first access — this happens in the UI thread, so onCreate must execute quickly.

Data Protection Through Permissions

Content Provider allows managing data access at two levels: read permissions and write permissions. They are set in the manifest with the android:readPermission and android:writePermission attributes. If the client application does not have the corresponding permission, the system rejects the call with a SecurityException.

URI-Level Permissions

Android supports temporary permissions through the FLAG_GRANT_READ_URI_PERMISSION and FLAG_GRANT_WRITE_URI_PERMISSION flags. This is useful when an application passes a file URI to another application via Intent — the recipient gets access only to that specific URI for a limited time. The system revokes the temporary permission after the receiving application finishes.

For system providers, Android requires specifying specific permissions in the application manifest. For example, accessing contacts requires READ_CONTACTS, and accessing the calendar requires READ_CALENDAR. Starting from Android 6, these permissions are requested at runtime rather than during installation.

Frequently Asked Questions

What is Content Provider in Android?

Content Provider is an Android component that provides a standard interface for data exchange between applications through ContentResolver. It abstracts the storage method (SQLite, files, network) and ensures secure data access with read and write permission control.

What is authority in Content Provider?

Authority is a unique provider identifier string specified in AndroidManifest.xml. It forms the first part of the URI content://authority/path and is used by the system to route ContentResolver calls to the correct provider. The authority must be unique among all applications on the device.

How does UriMatcher work in Content Provider?

UriMatcher maps URIs to numeric codes. You add patterns via addURI, then call match to get the code for an incoming URI. This allows the query, insert, update, and delete methods to determine which table or record is being requested and perform the corresponding database operation.

Do I need to close the Cursor after working with ContentResolver?

Yes, the Cursor must always be closed after use. If the Cursor is not closed, a memory leak occurs because it holds a Binder reference to the provider's data. In Kotlin, use the use function for automatic closing, and in Java — try-with-resources or cursor.close() in a finally block.

How is Content Provider different from SQLiteDatabase?

Content Provider is a component for inter-application data access, while SQLiteDatabase is an internal storage mechanism for a single application. Content Provider provides a URI interface and permission control, whereas SQLiteDatabase works directly with the database without OS-level security mechanisms.

Summary

  • Content Provider is a standard Android component for secure data exchange between applications through the unified ContentResolver interface.
  • URI of the scheme content://authority/path/id identifies the provider, table, and specific record — each segment has a strict purpose.
  • UriMatcher simplifies parsing of incoming URIs inside the provider, eliminating manual string parsing in each CRUD method.
  • The provider is registered in AndroidManifest.xml with authorities and exported attributes — this is a system mechanism without which the provider will not work.
  • ContentValues are passed to insert and update as key-value pairs, and a Cursor is returned from query for iterating over results.
  • readPermission and writePermission in the manifest control data access, while FLAG_GRANT_URI_PERMISSION provides temporary access to a specific URI.
  • For asynchronous data loading from Content Provider, use CursorLoader, Room with ContentProvider, or LoaderManager — this prevents blocking the UI thread.

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also