Table of contents
1.
Introduction
2.
Create Content Provider
3.
Methods of Content Provider
4.
Content URI
5.
Content Provider Implementation
6.
FAQs
7.
Key Takeaways
Last Updated: Mar 27, 2024

Android Content Providers

Author Rahul Sain
1 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

A content provider component sends data from one application to another. The methods of the ContentResolver class handle such requests. A content provider can store its data in various forms, including databases, files, and even through a network.

In this article, we will learn about Android Content providers and their implementation. But before jumping into this, we would strongly recommend learning about Android Activities.

We will now look into creating a Content Provider in the upcoming section.

Create Content Provider

Content providers enable you to consolidate Content in one location and have several apps access it as needed. A content provider is similar to a database in that you may query it, alter its Content, and add or delete Content using the insert(), update(), delete(), and query() functions. This information is saved in an SQLite database that other apps can access in most cases.

A content provider should be a subclass of the ContentProvider class and must implement a set of standard APIs that allow other apps to make transactions.

To build your content provider, follow a few simple steps.

  • To begin, construct a Content Provider class that extends the ContentProviderbaseclass.
  • Second, you must specify the URI address of your content provider, which will be utilized to access the Content.
  • Then, to keep the material, you'll need to construct your database. Typically, Android employs the SQLite database, and the framework must override the onCreate() function, which uses the SQLite Open Helper method to construct or open the Provider's database. When your application is launched, the main application thread calls the onCreate() handler of each content provider.
  • Now, we can implement Content Provider queries to perform various database-specific operations.
  • Finally, register your Content Provider in your activity file using the <provider> tag.

Methods of Content Provider

  • onCreate()  When the receiver is formed, this function in Android initializes the Provider.
  • query()  In Android, it receives a query request from the user and responds with a cursor.
  • insert()  We use this method to insert data into our content provider.
  • update()  This function updates existing data in a row and returns the updated row data.
  • delete()  Removes existing data from the content provider.
  • getType()  This function returns the Multipurpose Internet Mail Extension data type to the supplied Content URI.

Content URI

The universal resource identifiers (URIs) that identify the data in content providers are known as Content URIs. A content URI contains two elements: Authority, which is the symbolic name of the Provider, and Path, which is a name that leads to the data. Every content provider method takes a URI as an argument.

Syntax

content://<authority>/<path>/<optional_id>
  • content:// – It is always present and serves as the scheme portion of the URI.
  • authority – It is the content provider's unique name, such as photos or contacts. It's a string that can identify the complete content source.
  • path – It is frequently used to identify some or all of the Provider's data. The path is usually used to distinguish between specific tables.
  • optional id - id is used to retrieve a specific record in a file. We only utilize this when we need to retrieve a particular document rather than the entire file. It is a numerical identification used to access a specific data table row.

Content Provider Implementation

We'll make a file called ContentProvider, and under it, a Java file called YourProvider.kt.

Code

package com.codingninjas.contentprovider

import android.content.*
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteException
import android.database.sqlite.SQLiteOpenHelper
import android.database.sqlite.SQLiteQueryBuilder
import android.net.Uri

class YourProvider : ContentProvider() {
    companion object {
        private const val PROVIDER_NAME = "com.codingninjas.contentprovider.UserProvider"
        private const val URL = "content://$PROVIDER_NAME/users"
        val CONTENT_URI: Uri = Uri.parse(URL)
        const val id = "id"
        const val uriCode = 1
        var uriMatcher: UriMatcher? = null
        private val values: HashMap<String, String>? = null
        const val DATABASE_NAME = "EmpDB"
        const val TABLE_NAME = "Employees"
        const val DATABASE_VERSION = 1
        const val CREATE_DB_TABLE = (" CREATE TABLE " + TABLE_NAME
                + " (id INTEGER PRIMARY KEY AUTOINCREMENT, "
                + " name TEXT NOT NULL);")

        init {
            uriMatcher = UriMatcher(UriMatcher.NO_MATCH)
            uriMatcher!!.addURI(PROVIDER_NAME, "users", uriCode)
            uriMatcher!!.addURI(PROVIDER_NAME, "users/*", uriCode)
        }
    }

    override fun getType(uri: Uri): String {
        if (uriMatcher!!.match(uri) == uriCode) {
            return "cn.android.dir/usersData"
        }
        throw IllegalArgumentException("Unsupported URI: $uri")
    }

    override fun onCreate(): Boolean {
        val context = context
        val dbHelper = DatabaseHelper(context)
        db = dbHelper.writableDatabase
        return db != null
    }

    override fun query(
        uri: Uri, projection: Array<String>?, selection: String?,
        selectionArgs: Array<String>?, sortOrder: String?
    ): Cursor? {
        var sortOrder = sortOrder
        val qb = SQLiteQueryBuilder()
        qb.tables = TABLE_NAME
        if (uriMatcher!!.match(uri) == uriCode) {
            qb.projectionMap = values
        } else {
            throw IllegalArgumentException("Unknown URI $uri")
        }
        if (sortOrder == null || sortOrder == "") {
            sortOrder = id
        }
        val c = qb.query(
            db, projection, selection, selectionArgs, null,
            null, sortOrder
        )
        c.setNotificationUri(context!!.contentResolver, uri)
        return c
    }

    override fun insert(uri: Uri, values: ContentValues?): Uri {
        val rowID = db!!.insert(TABLE_NAME, "", values)
        if (rowID > 0) {
            val uri1 = ContentUris.withAppendedId(CONTENT_URI, rowID)
            context!!.contentResolver.notifyChange(uri1, null)
            return uri1
        }
        throw SQLiteException("Failed to add a record into $uri")
    }

    override fun update(
        uri: Uri, values: ContentValues?, selection: String?,
        selectionArgs: Array<String>?
    ): Int {
        val count: Int = if (uriMatcher!!.match(uri) == uriCode) {
            db!!.update(TABLE_NAME, values, selection, selectionArgs)
        } else {
            throw IllegalArgumentException("Unknown URI $uri")
        }
        context!!.contentResolver.notifyChange(uri, null)
        return count
    }

    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
        val count: Int = if (uriMatcher!!.match(uri) == uriCode) {
            db!!.delete(TABLE_NAME, selection, selectionArgs)
        } else {
            throw IllegalArgumentException("Unknown URI $uri")
        }
        context!!.contentResolver.notifyChange(uri, null)
        return count
    }

    private var db: SQLiteDatabase? = null

    private class DatabaseHelper(context: Context?) :
        SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) {
        override fun onCreate(db: SQLiteDatabase) {
            db.execSQL(CREATE_DB_TABLE)
        }

        override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
            db.execSQL("DROP TABLE IF EXISTS $TABLE_NAME")
            onCreate(db)
        }
    }
}

Now, in MainActivity.kt, write the following code:

Code

package com.codingninjas.contentprovider

import android.content.ContentValues
import android.net.Uri
import android.os.Bundle
import android.view.MotionEvent
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        val imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
        imm.hideSoftInputFromWindow(currentFocus!!.windowToken, 0)
        return true
    }

    fun onClickAddDetails(view: View?) {
        val values = ContentValues()
        values.put(
            YourProvider.name,
            (findViewById<View>(R.id.txtName) as EditText).text.toString()
        )
        contentResolver.insert(YourProvider.CONTENT_URI, values)
        Toast.makeText(baseContext, "New Record Inserted", Toast.LENGTH_LONG).show()
    }

    fun onClickShowDetails(view: View?) {
        val resultView = findViewById<View>(R.id.res) as TextView
        val cursor = contentResolver.query(
            Uri.parse("content://com.codingninjas.contentprovider.UserProvider/users"),
            null,
            null,
            null,
            null
        )
        if (cursor!!.moveToFirst()) {
            val strBuild = StringBuilder()
            while (!cursor.isAfterLast) {
                strBuild.append(
                    """
                       
                        ${cursor.getString(cursor.getColumnIndex("id"))}-
                        """.trimIndent() + cursor.getString(
                        cursor.getColumnIndex("name")
                    )
                )
                cursor.moveToNext()
            }
            resultView.text = strBuild
        } else {
            resultView.text = "No Records Found"
        }
    }
}

After that, open activity main.xml and write the following code, where we've designed the application's layout:

Code

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="50dp"
        android:layout_marginEnd="50dp"
        android:text="Coding Ninjas"
        android:textColor="#FF5252"
        android:textSize="40sp" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="50dp"
        android:layout_marginEnd="50dp"
        android:layout_marginTop="50dp"
        android:text="Coding Ninjas User" />

    <EditText
        android:id="@+id/txtName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="50dp"
        android:layout_marginEnd="50dp"
        android:ems="20" />

    <Button
        android:id="@+id/btnAdd"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="50dp"
        android:layout_marginEnd="50dp"
        android:onClick="onClickAddDetails"
        android:text="Add User" />

    <Button
        android:id="@+id/btnRetrieve"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="50dp"
        android:layout_marginEnd="50dp"
        android:onClick="onClickShowDetails"
        android:text="Show Users" />

    <TextView
        android:id="@+id/res"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="50dp"
        android:layout_marginEnd="50dp"
        android:clickable="false"
        android:ems="20" />

</LinearLayout>

Write the following code in the AndroidManifest.xml file:

Code

<application>
 
        <provider
            android:authorities="com.codingninjas.contentprovider.UserProvider"
            android:name="com.codingninjas.contentprovider.YourProvider"
            android:exported="false">
        </provider>

    </application>

Following that, you'll see an application that looks like this:

Output

                    

When we click on Add User, it will store the text we passed to EditText into our database. By Clicking on Show User, we can see the stored data throughout any app.

FAQs

  1. Is SQLite a content provider?
    A SQLite database built on Android by one program is solely accessible to that application and cannot be accessed by other applications. As a result, if you need to communicate data between applications, you should use the content provider paradigm, as advised by Android.
     
  2. How do I update my content provider on Android?
    You can use insert/update query. insert(Uri, ContentValues) adds new data to the content provider. update(Uri, ContentValues, Bundle) changes the content provider's existing data.
     
  3. Is content provider thread-safe?
    The ContentProvider lacks thread safety. We will generally find that no additional work is required on your part to prevent dangerous race situations.

Key Takeaways

In this article, we have extensively discussed Content Provider in Android and its example.

You can head over to our Android Development Course on the Coding Ninjas Website to dive deep into Android Development and build future applications.

We hope that this blog has helped you enhance your knowledge regarding content providers, their examples and if you would like to learn more, check out our articles on Sharing App Data in Android. Do upvote our blog to help other ninjas grow. Happy Coding!

Live masterclass