How To Create Android Custom Content Provider Example

This article will show you examples of how to create your own custom android content provider.

1. Custom Android Content Provider Example Overview.

  1. From below program diagram. We can see that generally there are two parts in a custom content provider example.
    create-and-call-custom-content-provider-diagram
  2. Custom content provider part: This part uses the SQLite database to store and manipulate user account data.
  3. Content provider consumer part: This part uses ContentResolver to invoke the method that the custom content provider provided.

2. Custom Content Provider Part Source Code.

  1. To learn how to create a custom content provider in theory, please read the article Android Custom Content Provider Introduction.
  2. To create a custom content provider, you need to create the below two java files and update the AndroidManifest.xml file.
    ./
    ├── app
    │   ├── build.gradle
    │   ├── proguard-rules.pro
    │   └── src
    │       ├── main
    │       │   ├── AndroidManifest.xml
    │       │   ├── java
    │       │   │   └── com
    │       │   │       └── dev2qa
    │       │   │           └── example
    │       │   │               ├── datasharing
    │       │   │               │   └── custom
    │       │   │               │       └── provider
    │       │   │               │           ├── AccountContentProvider.java
    │       │   │               │           └── AccountDBHelper.java

2.1 Custom Content Provider Class.

  1. This class must extend android.content.ContentProvider.
  2. To learn how to create it, please follow Android Custom Content Provider Introduction‘s How To Create Custom Content Provider Class In Android Studio part.
  3. AccountContentProvider.java
    package com.dev2qa.example.datasharing.custom.provider;
    
    import android.content.ContentProvider;
    import android.content.ContentValues;
    import android.content.UriMatcher;
    import android.database.Cursor;
    import android.database.sqlite.SQLiteDatabase;
    import android.net.Uri;
    import android.util.Log;
    
    public class AccountContentProvider extends ContentProvider {
    
        private static String TAG_ACCOUNT_CONTENT_PROVIDER = "CONTENT_PROVIDER";
    
        private AccountDBHelper accountDBHelper;
    
        private final String accountDBFile = "Account.db";
    
        private int dbVersion = 1;
    
        // Represent account table.
        public static final int ACCOUNT_DIR = 1;
    
        // Represent one row in account table.
        public static final int ACCOUNT_ITEM = 2;
    
        // The authority of account content provider.
        public static final String AUTHORITY = "com.dev2qa.account.provider";
    
        private static final String accountPath = "account";
    
        // Declare UriMatcher object.
        private static UriMatcher uriMatcher;
    
        // if content data mimetype is a table then use this prefix.
        private static final String mimeTypeDirPrefix = "vnd.android.cursor.dir/";
    
        // if content data mimetype is table rows then use this prefix.
        private static final String mimeTypeItemPrefix = "vnd.android.cursor.item/";
    
        // Base uri for this content provider.
        public static final String BASE_CONTENT_URI = "content://" + AUTHORITY + "/" + accountPath;
    
        // Initialize uriMatcher, add matched uri.
        static{
            uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
            // Match uri to account table.
            uriMatcher.addURI(AUTHORITY, accountPath, ACCOUNT_DIR);
            // Match uri to account table row.
            uriMatcher.addURI(AUTHORITY, accountPath+"/#", ACCOUNT_ITEM);
        }
    
    
        public AccountContentProvider() {
        }
    
        /* Delete data in account content provider. */
        @Override
        public int delete(Uri uri, String selection, String[] selectionArgs) {
            // Implement this to handle requests to delete one or more rows.
    
            // Return deleted rows count.
            int ret = 0;
    
            // Get account db object. Below code will create a SQLite database. 
            SQLiteDatabase accountDb = accountDBHelper.getWritableDatabase();
    
            // Get uri match code.
            int matchCode = uriMatcher.match(uri);
    
            if(matchCode==ACCOUNT_DIR)
            {
                // Delete all rows in account table.
                ret = accountDb.delete(AccountDBHelper.TABLE_NAME_ACCOUNT, selection, selectionArgs);
            }else if(matchCode==ACCOUNT_ITEM)
            {
                // Delete row with request row id.
                String accountId = uri.getPathSegments().get(1);
                String whereClause = " _id = ? ";
                String whereArgsArr[] = {accountId};
                ret = accountDb.delete(AccountDBHelper.TABLE_NAME_ACCOUNT, whereClause, whereArgsArr);
            }
    
            Log.d(TAG_ACCOUNT_CONTENT_PROVIDER, "Account content provider delete method is called.");
    
            return ret;
        }
    
        /* Get request uri data mimetype string. */
        @Override
        public String getType(Uri uri) {
            // TODO: Implement this to handle requests for the MIME type of the data at the given URI.
    
            // Data mimetype string format. vndPrefix/vnd.<authority>.<path>
            StringBuffer retBuf = new StringBuffer();
    
            // Parse request code.
            int requestCode = uriMatcher.match(uri);
    
            if(requestCode == ACCOUNT_DIR)
            {
                // If request table.
                retBuf.append(mimeTypeDirPrefix);
                retBuf.append("vnd.");
                retBuf.append(AUTHORITY);
                retBuf.append(".");
                retBuf.append(accountPath);
            }else if(requestCode == ACCOUNT_ITEM)
            {
                // If request table rows.
                retBuf.append(mimeTypeItemPrefix);
                retBuf.append("vnd.");
                retBuf.append(AUTHORITY);
                retBuf.append(".");
                retBuf.append(accountPath);
            }
    
            Log.d(TAG_ACCOUNT_CONTENT_PROVIDER, "Account content provider getType method is called.");
    
            return retBuf.toString();
        }
    
        /* Insert data into account content provider. */
        @Override
        public Uri insert(Uri uri, ContentValues values) {
            // TODO: Implement this to handle requests to insert a new row.
    
            // Return newly inserted uri object..
            Uri ret = null;
    
            // Get account db object.
            SQLiteDatabase accountDb = accountDBHelper.getWritableDatabase();
    
            // Get uri match code.
            int matchCode = uriMatcher.match(uri);
    
            // Both match code means insert data into account table.
            if(matchCode==ACCOUNT_DIR || matchCode==ACCOUNT_ITEM)
            {
                // Insert user data into SQLite database account table and get newly added account id..
                long newAccountId = accountDb.insert(AccountDBHelper.TABLE_NAME_ACCOUNT, null, values);
    
                // Create new account uri. Uri string format : "content://<authority>/path/id".
                String newAccountUriStr = "content://" + AUTHORITY + "/" + accountPath + "/" + newAccountId;
                ret = Uri.parse(newAccountUriStr);
            }
    
            Log.d(TAG_ACCOUNT_CONTENT_PROVIDER, "Account content provider insert method is called.");
    
            return ret;
        }
    
        @Override
        public boolean onCreate() {
            boolean ret = true;
            // Get Account database helper instance.
            accountDBHelper = new AccountDBHelper(getContext(), accountDBFile, null, dbVersion);
    
            Log.d(TAG_ACCOUNT_CONTENT_PROVIDER, "Account content provider onCreate method is called.");
    
            return ret;
        }
    
        /* Query content provider, return result Cursor object.*/
        @Override
        public Cursor query(Uri uri, String[] projection, String selection,
                            String[] selectionArgs, String sortOrder) {
            // TODO: Implement this to handle query requests from clients.
    
            Cursor ret = null;
    
            // Get account db object.
            SQLiteDatabase accountDb = accountDBHelper.getWritableDatabase();
    
            // Get uri match code.
            int matchCode = uriMatcher.match(uri);
    
            if(matchCode==ACCOUNT_DIR)
            {
                // Return all rows that match query condition in account table.
                ret = accountDb.query(AccountDBHelper.TABLE_NAME_ACCOUNT, projection, selection, selectionArgs, null, null, sortOrder);
            }else if(matchCode==ACCOUNT_ITEM)
            {
                // Update rows with request row id.
                String accountId = uri.getPathSegments().get(1);
                String whereClause = " _id = ? ";
                String whereArgsArr[] = {accountId};
                ret = accountDb.query(AccountDBHelper.TABLE_NAME_ACCOUNT, projection, whereClause, whereArgsArr, null, null, sortOrder);
            }
    
            Log.d(TAG_ACCOUNT_CONTENT_PROVIDER, "Account content provider query method is called.");
    
            return ret;
    
        }
    
        /* Update content provider data. */
        @Override
        public int update(Uri uri, ContentValues values, String selection,
                          String[] selectionArgs) {
            // TODO: Implement this to handle requests to update one or more rows.
    
            // Return updated rows count.
            int ret = 0;
    
            // Get account db object.
            SQLiteDatabase accountDb = accountDBHelper.getWritableDatabase();
    
            // Get uri match code.
            int matchCode = uriMatcher.match(uri);
    
            if(matchCode==ACCOUNT_DIR)
            {
                // Update all rows in account table.
                ret = accountDb.update(AccountDBHelper.TABLE_NAME_ACCOUNT, values, selection, selectionArgs);
            }else if(matchCode==ACCOUNT_ITEM)
            {
                // Update rows with request row id.
                String accountId = uri.getPathSegments().get(1);
                String whereClause = " _id = ? ";
                String whereArgsArr[] = {accountId};
                ret = accountDb.update(AccountDBHelper.TABLE_NAME_ACCOUNT, values, whereClause, whereArgsArr);
            }
    
            Log.d(TAG_ACCOUNT_CONTENT_PROVIDER, "Account content provider update method is called.");
    
            return ret;
        }
    }

2.2 Account SQLite Database Helper Class.

  1. This custom content provider will use below SQLite database helper class to create and store user account info.
  2. The database file is saved in android emulator /data/data/com.dev2qa.example/databases/Account.db file. You can open an android device monitor to browse it.
  3. If you can not open the data folder on the android device monitor by clicking it. You can run the below shell command in a dos window. Then you can get root permission to operate the folder.
    adb root
  4. AccountDBHelper.java
    package com.dev2qa.example.datasharing.custom.provider;
    
    import android.content.Context;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteOpenHelper;
    
    public class AccountDBHelper extends SQLiteOpenHelper {
    
        private Context ctx;
    
        public static final String TABLE_NAME_ACCOUNT = "account";
    
        public AccountDBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
            super(context, name, factory, version);
            this.ctx = ctx;
        }
    
        @Override
        public void onCreate(SQLiteDatabase sqLiteDatabase) {
            StringBuffer createAccountTableSqlBuf = new StringBuffer();
            createAccountTableSqlBuf.append("create table ");
            createAccountTableSqlBuf.append(TABLE_NAME_ACCOUNT);
            createAccountTableSqlBuf.append("( _id integer primary key autoincrement,");
            createAccountTableSqlBuf.append(" user_name text,");
            createAccountTableSqlBuf.append(" password text,");
            createAccountTableSqlBuf.append(" email text,");
            createAccountTableSqlBuf.append(" title text )");
    
            sqLiteDatabase.execSQL(createAccountTableSqlBuf.toString());
        }
    
        @Override
        public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
            if(newVersion > oldVersion) {
                sqLiteDatabase.execSQL("drop table " + TABLE_NAME_ACCOUNT);
                this.onCreate(sqLiteDatabase);
            }
        }
    }

2.3 Register Custom Content Provider In Android Manifest Xml File.

  1. AndroidManifest.xml
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
    
        <provider
            android:name=".datasharing.custom.provider.AccountContentProvider"
            android:authorities="com.dev2qa.account.provider"
            android:enabled="true"
            android:exported="true"></provider>
    </application>
  2. If you want to know how to invoke this custom content provider’s method to manipulate user account data, you can read the next article How To Invoke Custom Content Provider In Other Apps Examples.

1 thought on “How To Create Android Custom Content Provider Example”

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.