Easy Tutorial
❮ Android Broadcast Receivers Android Single Fragment ❯

Android - Content Provider

The Content Provider component provides data from one application to others upon request. These requests are handled by methods of the ContentResolver class. Content Providers can store data in various ways, such as in databases, files, or even over the network.

Sometimes, sharing data between applications is necessary, and Content Providers become very useful in such scenarios.

Content Providers allow content to be centralized, enabling multiple different applications to access it when needed. Their behavior is similar to databases. You can query and edit their content, using methods like insert(), update(), delete(), and query() to add or remove content. Most often, data is stored in an SQLite database.

Content Providers are implemented as subclasses of the ContentProvider class and need to implement a set of standard APIs to allow other applications to perform transactions.

public class MyApplication extends ContentProvider {

}

Content URI

To query a Content Provider, you need to specify the query string in the form of a URI with the following format:

<prefix>://<authority>/<data_type>/<id>

Here is a detailed explanation of each part of the URI:

Part Description
prefix Prefix: Always set to content://
authority Authority: Specifies the name of the Content Provider, such as contacts, browser, etc. For third-party Content Providers, it can be the full name, like cn.programmer.statusprovider
data_type Data Type: This indicates the type of data in this particular Content Provider. For example, if you want to get all contacts via the Content Provider Contacts, the data path is people, and the URI would be: content://contacts/people
id This specifies the particular record requested. For example, if you are looking for the contact with ID 5 in the Content Provider Contacts, the URI would look like this: content://contacts/people/5

Creating a Content Provider

Here are the simple steps to create your own Content Provider:

Here are some methods you need to override in the ContentProvider class to make your Content Provider work:

Example

This example explains how to create your own Content Provider. Let's follow these steps:

Step Description
1 Create an Android application using Android Studio, named Content Provider, under the package com.tutorialpro.contentprovider, and set up an empty activity.
2 Modify the main activity file MainActivity.java to add two new methods, onClickAddName() and onClickRetrieveStudents().
3 Create a new Java file StudentsProvider.java under the package com.tutorialpro.contentprovider to define the actual provider and associated methods.
4 Register the Content Provider in AndroidManifest.xml using the <provider.../> tag.
5 Modify the res/layout/activity_main.xml file to include a simple interface for adding student records.
6 No changes are needed for strings.xml, as Android Studio handles this file.
7 Start the Android emulator to run the application and verify the results of the changes made.

Below is the content of the modified main activity file src/com.tutorialpro.contentprovider/MainActivity.java. This file includes basic lifecycle methods and two new methods, onClickAddName() and onClickRetrieveStudents(), to handle user interactions.

package com.tutorialpro.contentprovider;

import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.content.ContentValues;
import android.content.CursorLoader;
import android.database.Cursor;
import android.view.Menu;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import com.tutorialpro.contentprovider.R;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    public void onClickAddName(View view) {
        // Add a new student record
        ContentValues values = new ContentValues();

        values.put(StudentsProvider.NAME,
                ((EditText)findViewById(R.id.editText2)).getText().toString());

        values.put(StudentsProvider.GRADE,
                ((EditText)findViewById(R.id.editText3)).getText().toString());

        Uri uri = getContentResolver().insert(
                StudentsProvider.CONTENT_URI, values);

        Toast.makeText(getBaseContext(),
                uri.toString(), Toast.LENGTH_LONG).show();
    }

    public void onClickRetrieveStudents(View view) {

        // Retrieve student records
        String URL = "content://com.example.provider.College/students";

        Uri students = Uri.parse(URL);
        Cursor c = managedQuery(students, null, null, null, "name");

        if (c.moveToFirst()) {
            do{
                Toast.makeText(this,
                        c.getString(c.getColumnIndex(StudentsProvider._ID)) +
                                ", " +  c.getString(c.getColumnIndex( StudentsProvider.NAME)) +
                                ", " + c.getString(c.getColumnIndex( StudentsProvider.GRADE)),
                        Toast.LENGTH_SHORT).show();
            } while (c.moveToNext());
        }
    }
}

Create a new file StudentsProvider.java under the package com.tutorialpro.contentprovider. Below is the content of src/com.tutorialpro.contentprovider/StudentsProvider.java.

package com.tutorialpro.contentprovider;

import java.util.HashMap;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;

import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;

import android.net.Uri;
import android.text.TextUtils;

public class StudentsProvider extends ContentProvider {

    static final String PROVIDER_NAME = "com.example.provider.College";

static final String URL = "content://" + PROVIDER_NAME + "/students"; static final Uri CONTENT_URI = Uri.parse(URL);

static final String _ID = "_id"; static final String NAME = "name"; static final String GRADE = "grade";

private static HashMap<String, String> STUDENTS_PROJECTION_MAP;

static final int STUDENTS = 1; static final int STUDENT_ID = 2;

static final UriMatcher uriMatcher; static { uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(PROVIDER_NAME, "students", STUDENTS); uriMatcher.addURI(PROVIDER_NAME, "students/#", STUDENT_ID); }

/**

/**

@Override
public void onCreate(SQLiteDatabase db) {
    db.execSQL(CREATE_DB_TABLE);
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    db.execSQL("DROP TABLE IF EXISTS " + STUDENTS_TABLE_NAME);
    onCreate(db);
}

}

@Override public boolean onCreate() { Context context = getContext(); DatabaseHelper dbHelper = new DatabaseHelper(context);

/**
 * Create a writeable database if it does not already exist.
 */
db = dbHelper.getWritableDatabase();
return (db == null) ? false : true;

}

@Override public Uri insert(Uri uri, ContentValues values) { /** * Add a new student record */ long rowID = db.insert(STUDENTS_TABLE_NAME, "", values);

/**
 * If the record is added successfully
 */
if (rowID > 0) {
    Uri _uri = ContentUris.withAppendedId(CONTENT_URI, rowID);
    getContext().getContentResolver().notifyChange(_uri, null);
    return _uri;
}
throw new SQLException("Failed to add a record into " + uri);

}

@Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); qb.setTables(STUDENTS_TABLE_NAME);

switch (uriMatcher.match(uri)) {
    case STUDENTS:
        qb.setProjectionMap(STUDENTS_PROJECTION_MAP);
        break;

    case STUDENT_ID:
        qb.appendWhere(_ID + "=" + uri.getPathSegments().get(1));
        break;

    default:
        throw new IllegalArgumentException("Unknown URI " + uri);
}

if (sortOrder == null || sortOrder == "") {
    /**
     * By default, sort by student name
     */
    sortOrder = NAME;
}
Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, sortOrder);

/**
 * Register to watch a content URI for changes
 */
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;

}

@Override public int delete(Uri uri, String selection, String[] selectionArgs) { int count = 0;

switch (uriMatcher.match(uri)) {
    case STUDENTS:
        count = db.delete(STUDENTS_TABLE_NAME, selection, selectionArgs);
        break;

    case STUDENT_ID:
        String id = uri.getPathSegments().get(1);
        count = db.delete(STUDENTS_TABLE_NAME, _ID + " = " + id +
                (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs);
        break;

    default:
        throw new IllegalArgumentException("Unknown URI " + uri);
}

getContext().getContentResolver().notifyChange(uri, null);
return count;

}

@Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { int count = 0;

switch (uriMatcher.match(uri)) {
    case STUDENTS:
        count = db.update(STUDENTS_TABLE_NAME, values, selection, selectionArgs);
        break;

    case STUDENT_ID:
        count = db.update(STUDENTS_TABLE_NAME, values, _ID + " = " + uri.getPathSegments().get(1) +
                (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs);
        break;

    default:
        throw new IllegalArgumentException("Unknown URI " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;

}

@Override public String getType(Uri uri) { switch (uriMatcher.match(uri)) { case STUDENTS: return "vnd.android.cursor.dir/vnd.example.students";

    case STUDENT_ID:
        return "vnd.android.cursor.item/vnd.example.students";

    default:
        throw new IllegalArgumentException("Unsupported URI: " + uri);
}

}

/**
 * Get all student records
 */
case STUDENTS:
    return "vnd.android.cursor.dir/vnd.example.students";

/**
 * Get a specific student
 */
case STUDENT_ID:
    return "vnd.android.cursor.item/vnd.example.students";

default:
    throw new IllegalArgumentException("Unsupported URI: " + uri);
}
}

Here is the modified AndroidManifest.xml file. A <provider.../> tag has been added here to include our content provider:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tutorialpro.contentprovider"
    android:versionCode="1"
    android:versionName="1.0" >

    &lt;uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="22" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

        <activity
            android:name="com.tutorialpro.contentprovider.MainActivity"
            android:label="@string/app_name" >

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

        </activity>

        <provider android:name="StudentsProvider"
            android:authorities="com.example.provider.College" >
        </provider>

    </application>

</manifest>

Below is the content of the res/layout/activity_main.xml file:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Content Provider Example"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:textSize="30dp" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="www.tutorialpro.org"
        android:textColor="#ff87ff09"
        android:textSize="30dp"
        android:layout_below="@+id/textView1"
        android:layout_centerHorizontal="true" />

    <ImageButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/imageButton"
        android:src="@drawable/ic_launcher"
        android:layout_below="@+id/textView2"
        android:layout_centerHorizontal="true" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/button2"
        android:text="Add"
        android:layout_below="@+id/editText3"
        android:layout_alignRight="@+id/textView2"
        android:layout_alignEnd="@+id/textView2"
        android:layout_alignLeft="@+id/textView2"
        android:layout_alignStart="@+id/textView2"
        android:onClick="onClickAddName"/>

    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/editText"
        android:layout_below="@+id/imageButton"
        android:layout_alignRight="@+id/imageButton"
        android:layout_alignEnd="@+id/imageButton" />

    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/editText2"
        android:layout_alignTop="@+id/editText"
        android:layout_alignLeft="@+id/textView1"
        android:layout_alignStart="@+id/textView1"
        android:layout_alignRight="@+id/textView1"
        android:layout_alignEnd="@+id/textView1"
        android:hint="Name"
        android:textColorHint="@android:color/holo_blue_light" />

    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/editText3"
        android:layout_below="@+id/editText"
        android:layout_alignLeft="@+id/editText2"
        android:layout_alignStart="@+id/editText2"
        android:layout_alignRight="@+id/editText2"
        android:layout_alignEnd="@+id/editText2"
        android:hint="Grade"
        android:textColorHint="@android:color/holo_blue_bright" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Query"
        android:id="@+id/button"
        android:layout_below="@+id/button2"
        android:layout_alignRight="@+id/editText3"
        android:layout_alignEnd="@+id/editText3"
        android:layout_alignLeft="@+id/button2"
        android:layout_alignStart="@+id/button2"
        android:onClick="onClickRetrieveStudents"/>

</RelativeLayout>

Ensure that the res/values/strings.xml file contains the following:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">Content Provider</string>
    <string name="action_settings">Settings</string>

</resources>

Let's run the Content Provider application we just modified. I assume you have already created an AVD during the setup environment. Open the activity file in your project and click on the toolbar.

Enter a name and grade, and click the "Add" button, which will add a student record to the data and delete a message at the bottom. The message content displays the content provider URI containing the number of records added to the database. This operation uses the insert() method. Repeat this process to add more students to our content provider's database.

Once you have finished adding database records, it's time to request the records back from the content provider. Click the "Query" button, which will retrieve and display all data records through the implemented query() method.

You can provide callback methods in MainActivity.java to write update and delete operations, and modify the user interface to add update and delete functions.

You can use existing content providers, such as contacts, in this way. You can also develop an excellent database-oriented application in this way, performing all database operations such as read, write, update, and delete as demonstrated in the example above.

❮ Android Broadcast Receivers Android Single Fragment ❯