Android Custom Content Provider

By | January 31, 2015

Content Provider is one of the building block of android application like activity , service , broadcast . Content Providers are used to share data between two application , these data are stored in database or flat files , In most cases this data is stored in an SQlite database .

In Android Every applications runs in its own process with its own permissions which keeps an application data hidden from another application , Without content providers accessing data of other apps would be a mess.

There are number of Standard Content Providers Available in android API to work with which are defined inside android.provider  package like ContactsContract ,Browser, UserDictionary, MediaStore etc..


In this tutorial we will create a custom content provider and below the video demo of final Output .

Database

Table Structure

Table name : member

   Field     Type Key
_id    INTEGER       PRIMARY KEY AUTOINCREMENT  
name TEXT

Create DBhelper Class which must be subclassed to SQLiteOpenHelper , and create a constructor for this class and call the super() method which takes database name and database version as a parameter to it .

override the onCreate() and onUpgrade() for creating and upgrading the database respectively .

file : DBhelper.java

package com.pavan.cpdemo.database;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class DBhelper extends SQLiteOpenHelper {

    // TABLE INFORMATTION
    public static final String TABLE_MEMBER = “member“;
    public static final String MEMBER_ID = “_id“;
    public static final String MEMBER_NAME = “name“;

    // DATABASE INFORMATION
    static final String DB_NAME = “MEMBER.DB”;
    static final int DB_VERSION = 1;

    // TABLE CREATION STATEMENT
    private static final String CREATE_TABLE = “create table ” + TABLE_MEMBER
            + “(” + MEMBER_ID + ” INTEGER PRIMARY KEY AUTOINCREMENT, “
            + MEMBER_NAME + ” TEXT NOT NULL);”;

    public DBhelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
    }

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

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

Custom Content Provider

 To create your custom content provider you have to define a class which extends android.content.ContentProvider.and declare this class as content provider in the Android manifest file where the property android:authorities specifies the unique identity for accessing content provider.

    <provider
        android:name=”com.pavan.cpdemo.provider.CustomProvider”
        android:authorities=”com.pavan.cpdemo.CustomProvider”
        …..
        …..
        >
    </provider>

The Most Important Part Accessing or Dealing With Content Provider is the Content URI.

 prefix://authority/data_type/id

Part Description
  prefix The Prefix is always set with content://  
 authority This Specifies the name of the content provider  , This Part should unique for every content providers , android document recommends to use fully qualified class name of your content provider
 data_type  This Part Specifies the type of the data that you are interested in , like the media content provider has the following types like image , audio and video
  id The Last part is the id , which specifies the particular record.
  1.  Create a Class CustomProvider Which extends ContentProvider .
  2.  Define the Content Provider URI address which will be used for accessing the content
  3.  Override the following methods of ContentProvider Class.
Method Description
  onCreate()      This Method is called when content provider is created .
  insert() This method is used for insert new record.
  query() This method returns cursor object which contents resultant query.
  update() This method is used for updating records.
  delete() This method is used for deleting records.
  getType() This method returns the MIME Type of the data of the given URI.       

file : CustomProvider.java

package com.pavan.cpdemo.provider;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import com.pavan.cpdemo.database.DBhelper;

public class CustomProvider extends ContentProvider {

    // unique identifier
    public static final String AUTH = “com.pavan.cpdemo.CustomProvider“;
    static final String URL = “content://” + AUTH + “/” + DBhelper.TABLE_MEMBER;
    public static final Uri CONTENT_URI = Uri.parse(URL);

    static final int members = 1;
    static final int member_id = 2;

    DBhelper dbhelper;

    private static UriMatcher uriMatcher;

    static {
        uriMatcher = new UriMatcher(uriMatcher.NO_MATCH);
        uriMatcher.addURI(AUTH, DBhelper.TABLE_MEMBER, members);
        uriMatcher.addURI(AUTH, DBhelper.TABLE_MEMBER + “/#“, member_id);
    }

    @Override
    public boolean onCreate() {
        dbhelper = new DBhelper(getContext());
        return true;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        SQLiteDatabase db;
        db = dbhelper.getWritableDatabase();

        if (uriMatcher.match(uri) == members) {
            long rowID = db.insert(DBhelper.TABLE_MEMBER, null, values);

            if (rowID > 0) {
                Uri _uri = ContentUris.withAppendedId(CONTENT_URI, rowID);
                getContext().getContentResolver().notifyChange(uri, null);
                return _uri;
            }
        }
        db.close();

        return null;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {

        SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
        queryBuilder.setTables(DBhelper.TABLE_MEMBER);

        SQLiteDatabase db;
        db = dbhelper.getWritableDatabase();

        Cursor cursor = queryBuilder.query(db, projection, selection,
                selectionArgs, null, null, sortOrder);
        cursor.setNotificationUri(getContext().getContentResolver(), uri);

        return cursor;
    }

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

        SQLiteDatabase db;
        db = dbhelper.getWritableDatabase();
        int rowsUpdated = 0;

        switch (uriMatcher.match(uri)) {
          case members:
              rowsUpdated = db.update(DBhelper.TABLE_MEMBER, values, selection,
                    selectionArgs);
            break;

        case member_id:
            String id = uri.getLastPathSegment();
            rowsUpdated = db.update(DBhelper.TABLE_MEMBER, values,
                    DBhelper.MEMBER_ID + “=” + id, null);
            break;
        }

        getContext().getContentResolver().notifyChange(uri, null);
        return rowsUpdated;
    }

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

        SQLiteDatabase db;
        db = dbhelper.getWritableDatabase();
        int rowsDeleted = 0;

        switch (uriMatcher.match(uri)) {
        case members:
            rowsDeleted = db.delete(DBhelper.TABLE_MEMBER, selection,
                    selectionArgs);
            break;

        case member_id:
            String id = uri.getLastPathSegment();
            rowsDeleted = db.delete(DBhelper.TABLE_MEMBER, DBhelper.MEMBER_ID
                    + “=” + id, null);
            break;

        }
        getContext().getContentResolver().notifyChange(uri, null);
        return rowsDeleted;
    }

    @Override
    public String getType(Uri uri) {

        switch (uriMatcher.match(uri)) {
        /**
         * Get all member records
         */
        case members:
            returnvnd.android.cursor.dir/members“;
            /**
             * Get a particular member
             */
        case member_id:
            returnvnd.android.cursor.item/member_id“;
        default:
            throw new IllegalArgumentException(“Unsupported URI: ” + uri);
        }
    }

}

Inserting And Reading

Create XML layout (activity_main.xml) With EditText , Button and ListView Widget .

file : activity_main.xml

<LinearLayout
    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:orientation=”vertical”
    tools:context=”com.pavan.cp_demo.MainActivity”
    android:padding=”10dp”>

    <EditText

        android:id=”@+id/editText1″
        android:layout_width=”match_parent”
        android:layout_height=”wrap_content”
        android:ems=”10″ >

        <requestFocus />

    </EditText>

    <Button

        android:id=”@+id/button1″
        android:layout_width=”match_parent”
        android:layout_height=”wrap_content”
        android:onClick=”insertdata”
        android:text=”Insert” />

    <ListView

        android:id=”@+id/listView1″
        android:layout_width=”match_parent”
        android:layout_height=”wrap_content” >
    </ListView>

</LinearLayout>



Create XML layout (view_member_entry.xml) which represents the items of the listview. 

file : view_member_entry.xml

<?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/member_id”
        android:layout_width=”fill_parent”
        android:layout_height=”wrap_content”
        android:visibility=”gone” />

    <TextView

        android:id=”@+id/member_name”
        android:layout_width=”fill_parent”
        android:layout_height=”wrap_content”
        android:padding=”15dp”
        android:textSize=”17sp”
        android:textStyle=”bold”
        android:textColor=”#000000″/>

</LinearLayout>

  1. Create a Class MainActivity which extends activity class and set the content of this class with above defined xml file (activity_main.xml).
  2. To Insert data Using Content Resolver Class Object (getContentResolver) call the insert by passing URI and ContentValues as parameter to it . 
  3. Using Loader I am loading data into listview using SimpleCusorAdapter.

file : MainActivity.java

package com.pavan.cpdemo;

import android.annotation.SuppressLint;
import android.app.LoaderManager;
import android.content.ContentValues;
import android.content.CursorLoader;
import android.content.Intent;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import com.pavan.cpdemo.database.DBhelper;
import com.pavan.cpdemo.provider.CustomProvider;

public class MainActivity extends FragmentActivity implements
        LoaderManager.LoaderCallbacks<Cursor> {

    EditText et;
    ListView lv;

    private SimpleCursorAdapter adapter;

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

        et = (EditText) findViewById(R.id.editText1);
        lv = (ListView) findViewById(R.id.listView1);

        getLoaderManager().initLoader(0, null, this);

        String[] from = new String[] { DBhelper.MEMBER_ID, DBhelper.MEMBER_NAME };
        int[] to = new int[] { R.id.member_id, R.id.member_name };

        adapter = new SimpleCursorAdapter(getApplicationContext(),
                R.layout.view_member_entry, null, from, to, 0);

        lv.setAdapter(adapter);
        lv.setOnItemClickListener(new ListitemClickListener());

    }

    class ListitemClickListener implements ListView.OnItemClickListener {

        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position,
                long id) {

            TextView memID_tv, memName_tv;

            memID_tv = (TextView) view.findViewById(R.id.member_id);
            memName_tv = (TextView) view.findViewById(R.id.member_name);

            String member_id = memID_tv.getText().toString();
            String member_name = memName_tv.getText().toString();

            Intent i = new Intent(getApplicationContext(), Modify_member.class);
            i.putExtra(“member_id“, member_id);
            i.putExtra(“member_name“, member_name);

            startActivity(i);

        }
    }

    public void insertdata(View view) {

        String name = et.getText().toString();

        ContentValues values = new ContentValues();
        values.put(DBhelper.MEMBER_NAME, name);

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

        et.setText(null);

    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        String[] allColumns = new String[] { DBhelper.MEMBER_ID,
                DBhelper.MEMBER_NAME };

        CursorLoader cursorLoader = new CursorLoader(getApplicationContext(),
                CustomProvider.CONTENT_URI, allColumns, null, null, null);

        return cursorLoader;
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        adapter.swapCursor(cursor);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        adapter.swapCursor(null);
    }
}

Updating And Deleting 

Create a XML layout (modify_member.xml) with one EditText and Two Buttons Widgets.

file : modify_member.xml

<?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”
    android:padding=”20dp” >

    <EditText
        android:id=”@+id/edit_mem_id”
        android:layout_width=”match_parent”
        android:layout_height=”wrap_content”
        android:layout_marginTop=”40dp”
        android:ems=”10″ />

    <LinearLayout
        android:layout_width=”match_parent”
        android:layout_height=”match_parent”
        android:gravity=”center_horizontal”
        android:orientation=”horizontal” >

        <Button
            android:id=”@+id/update_bt_id”
            android:layout_width=”wrap_content”
            android:layout_height=”wrap_content”
            android:onClick=”updateData”
            android:text=”Update” />

        <Button
            android:id=”@+id/delete_bt_id”
            android:layout_width=”wrap_content”
            android:layout_height=”wrap_content”
            android:onClick=”deleteData”
            android:text=”Delete” />
    </LinearLayout>

</LinearLayout>

  1. Create a Class Modify_member which extends Activity and set the content of this activity with above defined xml layout (modify_member.xml) .
  2. This Activity is opened on click of items of listview , this activity is opened as dialog which i have covered here in activity dialog .
  3. onClick of update button updateData() method is called inside this method the content of the record is updated using URI .
  4. onClick of delete button deleteData() method is called inside this method the content of the record is deleted using URI .

file : Modify_member.java

package com.pavan.cpdemo;

import android.app.Activity;
import android.content.ContentValues;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import com.pavan.cpdemo.database.DBhelper;
import com.pavan.cpdemo.provider.CustomProvider;

public class Modify_member extends Activity {

    EditText et;

    long memberID;
    Uri uri;
    String member_id, member_name;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.modify_member);

        et = (EditText) findViewById(R.id.edit_mem_id);

        Intent i = getIntent();
        member_id = i.getStringExtra(“member_id“);
        member_name = i.getStringExtra(“member_name“);

        et.setText(member_name);

        memberID = Long.parseLong(member_id);
        uri = Uri.parse(CustomProvider.CONTENT_URI + “/” + memberID);

    }

    public void updateData(View view) {

        String modified_name = et.getText().toString();
        ContentValues cv = new ContentValues();
        cv.put(DBhelper.MEMBER_NAME, modified_name);

        getContentResolver().update(uri, cv, null, null);

        finish();
    }

    public void deleteData(View view) {
        getContentResolver().delete(uri, null, null);

        finish();
    }

}

Updating

Deleting

Android Manifest

Finally Add the Application Component Like Activity and Content Provider inside the Manifest File .

file : AndroidManifest.xml

<?xml version=”1.0″ encoding=”utf-8″?>
<manifest
    xmlns:android=”http://schemas.android.com/apk/res/android”
    package=”com.pavan.cpdemo”
    android:versionCode=”1″
    android:versionName=”1.0″ >

    <uses-sdk
        android:minSdkVersion=”11″
        android:targetSdkVersion=”16″ />

    <application
        android:allowBackup=”true”
        android:icon=”@drawable/ic_launcher”
        android:label=”@string/app_name”
        android:theme=”@style/AppTheme” >
        <activity
            android:name=”.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>
        <activity
            android:name=”.Modify_member”
            android:theme=”@android:style/Theme.Holo.Light.Dialog”
            android:label=”Update / Delete”>
        </activity>

        <provider
            android:name=”com.pavan.cpdemo.provider.CustomProvider”
            android:authorities=”com.pavan.cpdemo.CustomProvider”>
        </provider>
    </application>

</manifest>