Write your own Custom Content Provider with SQLite Database Helper Class.

Write your own Custom Content Provider with SQLite Database Helper Class.

What is Content Provider

Part of the Android components. It helps other applications to access/edit/delete the data or files stored in your app. Without Content Provider, accessing the other application’s data is really harder and we should find another mechanism like cloud synching. Don’t forget to mention your content provider in Manifest file.

Android provides it’s own content providers to access Contact, CallLog, MediaStore, Browser, Calendar, Media files and Preferences. You can use them when you need. May be i will cover some of them in my future posts.

Content Provider also helps to pass data to widgets as well.

We use ContentResolver object in our context to communicate Content Provider as a client. ContentResolver has same method as Content Providers. The content provider receives data request from content resolver, process the request and return the result to content resolver.

 

Why do you need a Custom Content Provider.

Suppose you want to give access to your internal database data to other apps, or you want to provide access to your internal documents (video/audio/doc files) to other apps, You should give access by writing a Custom Content Provider.

 

Content Uri

Content Uri is a Resource identifier which identifies the data in a provider.  You always provide Content Uri as a parameter when you try to access from the Content Resolver. Content Uri has two major segments.

  1. Authority.
  2. Path.

in the following example Content Uri,

[code]

content://com.appsgit.employeeprovider/employee

[/code]

 

[code]com.appsgit.employeeprovider[/code] is called Authority.

 

[code]employee[/code] is the path.

 

the following Uri is targeted for 4th row of the employee table.

[code]

content://com.appsgit.employeeprovider/employee/4

[/code]

 

Content Provider Permission

Permission is important to access the content provider data. You should add permissions in the Android Manifest file, so the users know what kind of data the application is going to access when they install the application.

SQLite database you created for your app or for providers, are private to your application or providers.

If you don’t specify any permissions for the provider, other applications cannot access the provider.  for example, check the following code. i have provided read access to my provider, so other applications can read data from my provider using the unique name i provided.

 

[code]

<provider
 android:name="com.appsgit.employeeprovider.provider.EmployeeContentProvider"
 android:authorities="com.appsgit.employeeprovider"
 android:exported="true"
 android:label="EmployeeProvider"
 android:grantUriPermissions="true"
 android:readPermission="com.appsgit.employeeprovider.READ">

//provide unique name "com.appsgit.employeeprovider.READ"

[/code]

 

What is contract class

Contract class is a helper class for content providers. It contains provider related constants. It is good practice to write Contract class for each Content Provider.

For example, Contact Content provider has ContactContract class, which contains related constants of the ContactProvider.


Create a Simple Example Project

 

 

We will create a simple android project to show you how o create custom content provider and how to work with them.

Name the application as Employee Provider App which save/retrieve Employee’s personal data. Later we will show you how to access them from another application. We will create another Android project to show how to access content provider.

Check the full source code here.

 

Create an Employee POJO class 

 

[code]

package com.appsgit.employeeprovider.database;

/**
 * Created on 11/4/17.
 */

public class Emoployee {
    int id;
    String name;
    int age;
    String email;
    String phone;
    String address;

    public int getId() {
        return id;
    }

    public Emoployee setId(int id) {
        this.id = id;
        return this;
    }

    public String getName() {
        return name;
    }

    public Emoployee setName(String name) {
        this.name = name;
        return this;
    }

    public int getAge() {
        return age;
    }

    public Emoployee setAge(int age) {
        this.age = age;
        return this;
    }

    public String getEmail() {
        return email;
    }

    public Emoployee setEmail(String email) {
        this.email = email;
        return this;
    }

    public String getPhone() {
        return phone;
    }

    public Emoployee setPhone(String phone) {
        this.phone = phone;
        return this;
    }

    public String getAddress() {
        return address;
    }

    public Emoployee setAddress(String address) {
        this.address = address;
        return this;
    }
}

[/code]

 

 

Create EmployeeContract class

Writing Contract class for the content provider is a best practice and it is easy for us to find the necessary data in the same place.

Before we create helper class, we should create contract class for the provider. EmployeeContract class contains mostly about the database and provider details.

[code]

package com.appsgit.employeeprovider.database;

import android.content.ContentResolver;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;

/**
 A contract class is a public final class that contains constant definitions for the URIs,
 column names, MIME types, and other meta-data that related to the provider.
 The class establishes a contract between the provider and other applications by ensuring that the provider
 can be correctly accessed even if there are changes to the actual values of URIs, column names, and so forth.
 */

public class EmployeeContract {
    public static final int EMPLOYEE = 10;
    public static final int EMPLOYEE_ID = 20;

    public static final String EMPLOYEE_TABLE_NAME = "employee";
    public static final String COLUMN_ID = "_id";
    public static final String COLUMN_NAME = "name";
    public static final String COLUMN_AGE = "age";
    public static final String COLUMN_EMAIL = "email";
    public static final String COLUMN_PHONE = "phone";
    public static final String COLUMN_ADDRESS = "address";
    public static final String COLUMN_DELETED = "deleted";

   //Authority is unique string for the app.
    public static String AUTHORITY = "com.appsgit.employeeprovider";

    public static Uri EMPLOYEE_URI = Uri.parse("content://" + AUTHORITY + "/" + EMPLOYEE_TABLE_NAME);

    public static String EMPLOYEE_TABLE_CONTENT_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + "/" + AUTHORITY + "/" + EMPLOYEE_TABLE_NAME;

    public static String EMPLOYEE_TABLE_ITEM_CONTENT_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/" + AUTHORITY + "/" + EMPLOYEE_TABLE_NAME;


    public static final String CREATE_TABLE = "CREATE TABLE "
            + EMPLOYEE_TABLE_NAME
            + " (" + COLUMN_ID
            + " INTEGER primary key autoincrement, "
            + COLUMN_NAME + " TEXT not null, "
            + COLUMN_AGE + " INTEGER, "
            + COLUMN_EMAIL + " TEXT, "
            + COLUMN_PHONE + " TEXT, "
            + COLUMN_ADDRESS + " TEXT)";

    public static void onCreate(SQLiteDatabase db) {
       try {
           db.execSQL(CREATE_TABLE);
       } catch (Exception ex) {
           ex.printStackTrace();
       }
    }

}

[/code]

 

Create SQLITE Database Helper Class

 

[code]

package com.appsgit.employeeprovider.database;

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

public class EmployeeDataBaseHelper extends SQLiteOpenHelper {

    public static final String DATABASE_NAME = "employee.db";
    public static final int DATABASE_VERSION = 1;


    public EmployeeDataBaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        try {
            EmployeeContract.onCreate(sqLiteDatabase);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }



    //implement logics if you want to upgrade the current daatabse.
    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

    }

}

[/code]

 

Create Content Provider class.

 

We should create a sub class of ContentProvider. and implement all the necessary methods. check below EmployeeProvider class

[code]

package com.appsgit.employeeprovider.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 android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;

import com.appsgit.employeeprovider.database.EmployeeContract;
import com.appsgit.employeeprovider.database.EmployeeDataBaseHelper;

import java.util.Arrays;

/**
 *  Contains ContentProvider class methods. 
 */

public class EmployeeContentProvider extends ContentProvider {

    public static final String TAG = EmployeeContentProvider.class.getSimpleName();

    public static final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);

    String[] tableColumns = {EmployeeContract.COLUMN_ID, EmployeeContract.COLUMN_NAME, EmployeeContract.COLUMN_AGE, EmployeeContract.COLUMN_EMAIL, EmployeeContract.COLUMN_ADDRESS, EmployeeContract.COLUMN_PHONE};

    /*
     * Defines a handle to the database helper object. The MainDatabaseHelper class is defined
     * in a following snippet.
     */
    private EmployeeDataBaseHelper employeeDataBaseHelper;;

    // Holds the database object
    private SQLiteDatabase db;

    //add the URIs which is going to used by this provider.
    static {
        matcher.addURI(EmployeeContract.AUTHORITY, EmployeeContract.EMPLOYEE_TABLE_NAME, EmployeeContract.EMPLOYEE);
        matcher.addURI(EmployeeContract.AUTHORITY, EmployeeContract.EMPLOYEE_TABLE_NAME + "/#", EmployeeContract.EMPLOYEE_ID);
    }

    
    @Override
    public boolean onCreate() {
        employeeDataBaseHelper = new EmployeeDataBaseHelper(getContext());
        return true;
    }



    @Nullable
    @Override // query() Must return a Cursor object
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {

        int matchedUriType = matcher.match(uri);

        if (projection != null &&!Arrays.asList(tableColumns).containsAll(Arrays.asList(projection))) {
            throw new IllegalArgumentException("No Column found in Projection.");
        }

        SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
        queryBuilder.setTables(EmployeeContract.EMPLOYEE_TABLE_NAME);
        switch (matchedUriType) {
            case EmployeeContract.EMPLOYEE:

                break;

            case EmployeeContract.EMPLOYEE_ID:
                queryBuilder.appendWhere(EmployeeContract.COLUMN_ID + "=" + uri.getLastPathSegment());
                break;
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }

        db = employeeDataBaseHelper.getWritableDatabase();

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

        cursor.setNotificationUri(getContext().getContentResolver(), uri);

        return cursor;
    }

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        return null;
    }

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {

        db = employeeDataBaseHelper.getWritableDatabase();

        int matchedUriType = matcher.match(uri);

        long newId = 0;

        switch (matchedUriType) {
            case EmployeeContract.EMPLOYEE:
                newId = db.insert(EmployeeContract.EMPLOYEE_TABLE_NAME, null, contentValues);
                break;

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


// We cn use this as wellUri.parse(EmployeeContract.EMPLOYEE_URI.toString() + "/" + newId);

        return ContentUris.withAppendedId(uri, newId);
    }

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

        int rowDeleted = 0;

        db = employeeDataBaseHelper.getWritableDatabase();

        int matchedUriType = matcher.match(uri);

        switch (matchedUriType) {

            case EmployeeContract.EMPLOYEE:

                rowDeleted = db.delete(EmployeeContract.EMPLOYEE_TABLE_NAME, selection, selectionArgs);
                break;

            case EmployeeContract.EMPLOYEE_ID:

                String idTobeDeleted = uri.getLastPathSegment();

                if (selection != null && !selection.isEmpty()) {
                    rowDeleted = db.delete(
                            EmployeeContract.EMPLOYEE_TABLE_NAME,
                            EmployeeContract.COLUMN_ID + "=" + idTobeDeleted + " AND " + selection, selectionArgs);
                } else {
                    rowDeleted = db.delete(
                            EmployeeContract.EMPLOYEE_TABLE_NAME, EmployeeContract.COLUMN_ID + "=" + idTobeDeleted, null);
                }

                break;

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

        return rowDeleted;
    }

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

        int rowUpdated = 0;

        db = employeeDataBaseHelper.getWritableDatabase();

        int matchedUriType = matcher.match(uri);

        switch (matchedUriType) {
            case EmployeeContract.EMPLOYEE:
                rowUpdated = db.update(EmployeeContract.EMPLOYEE_TABLE_NAME, contentValues, selection, selectionArgs);
                break;

            case EmployeeContract.EMPLOYEE_ID:

                String idTobeUpdated = uri.getLastPathSegment();

                if (selection != null && !selection.isEmpty()) {
                    rowUpdated = db.update(
                            EmployeeContract.EMPLOYEE_TABLE_NAME,
                            contentValues,
                            EmployeeContract.COLUMN_ID + "=" + idTobeUpdated + " and " + selection,
                            selectionArgs);
                } else {
                    rowUpdated = db.update(
                            EmployeeContract.EMPLOYEE_TABLE_NAME,
                            contentValues,
                            EmployeeContract.COLUMN_ID + "=" + idTobeUpdated,
                            null);
                }
                break;

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

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

        return rowUpdated;
    }
}

[/code]

 

add the created custom content provider to Android Manifest file. Check my manifest file here,

 

[code]

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.appsgit.employeeprovider">

    <permission android:name="com.appsgit.employeeprovider.READ"/>

    <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">
        <activity android:name=".activities.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        <provider
            android:name="com.appsgit.employeeprovider.provider.EmployeeContentProvider"
            android:authorities="com.appsgit.employeeprovider"
            android:exported="true"
            android:label="EmployeeProvider"
            android:grantUriPermissions="true"
            android:readPermission="com.appsgit.employeeprovider.READ">

        </provider>

        <activity
            android:name=".activities.DetailActivity"
            android:label="@string/title_activity_detail"
            android:theme="@style/AppTheme.NoActionBar"></activity>
    </application>

</manifest>

[/code]

 

did you notice? i have added

[code]

<permission android:name="com.appsgit.employeeprovider.READ"/>

[/code]

 

If you don’t add the above permission element. Client app will throw exception like below.

 

[code]

com.appsgit.managerapp W/System.err: java.lang.SecurityException: Permission Denial: reading com.appsgit.employeeprovider.provider.EmployeeContentProvider uri content://com.appsgit.employeeprovider/employee from pid=1838, uid=10077 requires com.appsgit.employeeprovider.READ, or grantUriPermission()

[/code]

 

 

Now we have created most of the necessary class. Next we will see how to use them in the activity.

 

Create New Employee Activity

 

 

 

[code]

package com.appsgit.employeeprovider.activities;

import android.app.AlertDialog;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.support.annotation.BoolRes;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import com.appsgit.employeeprovider.R;
import com.appsgit.employeeprovider.database.EmployeeContract;
import com.appsgit.employeeprovider.provider.EmployeeContentProvider;

public class MainActivity extends AppCompatActivity {

    public static final String TAG = MainActivity.class.getSimpleName();
    public static final int REQUEST_CODE = 1000;

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

    public void saveData(View view) {
        try {
            TextView nameTextview = (TextView) findViewById(R.id.name);
            TextView addressTextview = (TextView) findViewById(R.id.address);
            TextView ageTextview = (TextView) findViewById(R.id.age);
            TextView emailTextview = (TextView) findViewById(R.id.email);
            TextView phoneTextview = (TextView) findViewById(R.id.phone);

            if (TextUtils.isEmpty(nameTextview.getText())) {
                showMessage("Name cannot be ampty.!", false);
                return;
            }

            ContentValues values = new ContentValues();
            values.put(EmployeeContract.COLUMN_NAME, nameTextview.getText().toString().trim());
            values.put(EmployeeContract.COLUMN_ADDRESS, addressTextview.getText().toString().trim());
            values.put(EmployeeContract.COLUMN_AGE, ageTextview.getText().toString().trim());
            values.put(EmployeeContract.COLUMN_EMAIL, emailTextview.getText().toString().trim());
            values.put(EmployeeContract.COLUMN_PHONE, phoneTextview.getText().toString().trim());

            //ContentResolver will access the Employee Content Provider
            Uri newUri = getContentResolver().insert(EmployeeContract.EMPLOYEE_URI, values);

            String newUserId = newUri.getLastPathSegment();

            showMessage("Successfully saved. New User ID is " + newUserId, true);


        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        TextView nameTextview = (TextView) findViewById(R.id.name);
        TextView addressTextview = (TextView) findViewById(R.id.address);
        TextView ageTextview = (TextView) findViewById(R.id.age);
        TextView emailTextview = (TextView) findViewById(R.id.email);
        TextView phoneTextview = (TextView) findViewById(R.id.phone);

        nameTextview.setText("");
        addressTextview.setText("");
        ageTextview.setText("");
        emailTextview.setText("");
        phoneTextview.setText("");
    }

    private void showMessage(String message, final Boolean successfullySaved) {
        try {
            AlertDialog alertDialog = new AlertDialog.Builder(MainActivity.this).create();
            alertDialog.setTitle("Message");
            alertDialog.setMessage(message);
            alertDialog.setCancelable(false);
            alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.dismiss();

                            if (successfullySaved) {
                                Intent intent = new Intent(MainActivity.this, DetailActivity.class);
                                startActivityForResult(intent, REQUEST_CODE);
                            }
                        }
                    });
            alertDialog.show();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

[/code]

 

the UI file is as follows,

 

[code]

<?xml version="1.0" encoding="utf-8"?>
<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"
    tools:layout_editor_absoluteX="8dp"
    tools:layout_editor_absoluteY="8dp"
    android:orientation="vertical"
    >
    <LinearLayout
        android:id="@+id/elementWrapper"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        tools:layout_editor_absoluteX="8dp"
        tools:layout_editor_absoluteY="8dp"
        android:orientation="vertical"
        android:padding="10dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:weightSum="3"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:layout_alignParentStart="true"
            android:layout_alignParentTop="true"
            android:background="@drawable/border">

            <LinearLayout
                android:layout_weight="1"
                android:layout_width="0dp"
                android:layout_height="50dp"
                android:orientation="vertical"
                android:layout_alignParentStart="true"
                android:layout_alignParentTop="true"
                android:background="@android:color/transparent"
                android:gravity="center_horizontal|center_vertical">

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:textColor="@android:color/black"
                    android:text="Name"
                    android:textAlignment="gravity"
                    android:textSize="15sp"/>

            </LinearLayout>

            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="50dp"
                android:layout_alignParentStart="true"
                android:layout_alignParentTop="true"
                android:layout_weight="2"
                android:background="@android:color/transparent"
                android:orientation="vertical">

                <EditText
                    android:id="@+id/name"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:padding="5dp"></EditText>

            </LinearLayout>

        </LinearLayout>

        <LinearLayout
            android:layout_weight="3"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentStart="true"
            android:layout_alignParentTop="true"
            android:background="@android:color/transparent"
            android:orientation="horizontal">
            <LinearLayout
                android:layout_weight="1"
                android:layout_width="0dp"
                android:layout_height="50dp"
                android:orientation="vertical"
                android:layout_alignParentStart="true"
                android:layout_alignParentTop="true"
                android:background="@android:color/transparent"
                android:gravity="center_horizontal|center_vertical">
                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:textColor="@android:color/black"
                    android:text="Age"
                    android:textAlignment="gravity"
                    android:textSize="15sp"/>

            </LinearLayout>

            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="50dp"
                android:layout_alignParentStart="true"
                android:layout_alignParentTop="true"
                android:layout_weight="2"
                android:background="@android:color/transparent"
                android:orientation="vertical">

                <EditText
                    android:id="@+id/age"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:padding="5dp"
                    android:inputType="number"></EditText>
            </LinearLayout>
        </LinearLayout>


        <LinearLayout
            android:layout_weight="3"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentStart="true"
            android:layout_alignParentTop="true"
            android:background="@android:color/transparent"
            android:orientation="horizontal">
            <LinearLayout
                android:layout_weight="1"
                android:layout_width="0dp"
                android:layout_height="50dp"
                android:orientation="vertical"
                android:layout_alignParentStart="true"
                android:layout_alignParentTop="true"
                android:background="@android:color/transparent"
                android:gravity="center_horizontal|center_vertical">
                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:textColor="@android:color/black"
                    android:text="Email"
                    android:textAlignment="gravity"
                    android:textSize="15sp"/>

            </LinearLayout>

            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="50dp"
                android:layout_alignParentStart="true"
                android:layout_alignParentTop="true"
                android:layout_weight="2"
                android:background="@android:color/transparent"
                android:orientation="vertical">

                <EditText
                    android:id="@+id/email"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:padding="5dp"
                    android:inputType="text"></EditText>
            </LinearLayout>
        </LinearLayout>

        <LinearLayout
            android:layout_weight="3"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentStart="true"
            android:layout_alignParentTop="true"
            android:background="@android:color/transparent"
            android:orientation="horizontal">
            <LinearLayout
                android:layout_weight="1"
                android:layout_width="0dp"
                android:layout_height="50dp"
                android:orientation="vertical"
                android:layout_alignParentStart="true"
                android:layout_alignParentTop="true"
                android:background="@android:color/transparent"
                android:gravity="center_horizontal|center_vertical">
                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:textColor="@android:color/black"
                    android:text="House Address"
                    android:textAlignment="gravity"
                    android:textSize="15sp"/>

            </LinearLayout>

            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="50dp"
                android:layout_alignParentStart="true"
                android:layout_alignParentTop="true"
                android:layout_weight="2"
                android:background="@android:color/transparent"
                android:orientation="vertical">

                <EditText
                    android:id="@+id/address"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:padding="5dp"
                    android:inputType="text"></EditText>
            </LinearLayout>
        </LinearLayout>

        <LinearLayout
            android:layout_weight="3"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentStart="true"
            android:layout_alignParentTop="true"
            android:background="@android:color/transparent"
            android:orientation="horizontal">
            <LinearLayout
                android:layout_weight="1"
                android:layout_width="0dp"
                android:layout_height="50dp"
                android:orientation="vertical"
                android:layout_alignParentStart="true"
                android:layout_alignParentTop="true"
                android:background="@android:color/transparent"
                android:gravity="center_horizontal|center_vertical">
                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:textColor="@android:color/black"
                    android:text="Phone"
                    android:textAlignment="gravity"
                    android:textSize="15sp"/>

            </LinearLayout>

            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="50dp"
                android:layout_alignParentStart="true"
                android:layout_alignParentTop="true"
                android:layout_weight="2"
                android:background="@android:color/transparent"
                android:orientation="vertical">

                <EditText
                    android:id="@+id/phone"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:padding="5dp"
                    android:inputType="phone"></EditText>
            </LinearLayout>
        </LinearLayout>



    </LinearLayout>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:layout_below="@+id/elementWrapper"
        android:background="@color/colorPrimary"
        android:gravity="center_horizontal"
        >
        <LinearLayout
            android:layout_weight="3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentStart="true"
            android:layout_alignParentTop="true"
            android:orientation="vertical">

            <Button
                android:background="@color/colorAccent"
                android:layout_width="200dp"
                android:layout_height="50dp"
                android:text="Save Employee (Save via Content Provider)"
                android:onClick="saveData"
                />
        </LinearLayout>
    </RelativeLayout>

</RelativeLayout>

[/code]

 

Create an xml call [code]border.xml[/code] file and copy  the below snippet to  the file,

 

[code]

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
        <solid android:color="@android:color/white" />
        <stroke android:width="2dip" android:color="#4fa5d5"/>
    </shape>
</selector>

[/code]

 

I have created another activity to show the total count of employees in the Employee content provider. Details page will be visible after you created the Employee.

 

 

[code]

package com.appsgit.employeeprovider.activities;

import android.database.Cursor;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import com.appsgit.employeeprovider.R;
import com.appsgit.employeeprovider.database.EmployeeContract;

public class DetailActivity extends AppCompatActivity {

    public static final String TAG = DetailActivity.class.getSimpleName();

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

        setContentView(R.layout.activity_detail);

        setResult(RESULT_OK);

        TextView textView = (TextView) findViewById(R.id.textView);

        Cursor cursor = getContentResolver().query(EmployeeContract.EMPLOYEE_URI, null, null, null, null);

        textView.setText("Employee count in Content Provider : " +  cursor.getCount());

    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
    }
}

[/code]

 

[code]

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.appsgit.employeeprovider.activities.DetailActivity">
    
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:textAlignment="center"
        android:padding="20dp"
        android:text="" />
</RelativeLayout>

[/code]

 

Saving  Employee data is done.!

 

 

 

You can find the source code for the above project in my personal github.


 

Now lets access the above content provider from another app.

 

 

Create Manager App to Access Employee Content Provider

 

I have created another Android project to access the above Employee Content Provider class.  I named the project as “ManagerApp“.  There will be one activity with a list of Employee name and emails.  Check my GitHub to download full source code for this project.

 

 

Create a manifest file and make necessary changes,

 

[code]

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.appsgit.managerapp">

    <uses-permission android:name="com.appsgit.employeeprovider.READ" />

    <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">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

[/code]

 

The below element is very important,

[code]

<uses-permission android:name=”com.appsgit.employeeprovider.READ” />

[/code]

 

 

Create Activity class an the xml file accordingly,

 

[code]

package com.appsgit.managerapp;

import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;

import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;

public class MainActivity extends Activity {

    public static final int READ_EMPLOYEE_DATA = 100;

    ListView listView;

    SimpleCursorAdapter simpleCursorAdapter;

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

        if (getActionBar() != null) {
            getActionBar().hide();
        }

        listView = findViewById(R.id.employeeList);

        loadData();

    }

    public void loadData() {
        try {
            Cursor cursor = getEmployeeDetails();

            String[] projection = {"name", "email"};

            int[] elementIds = {R.id.name, R.id.email};


            if (cursor != null) {
                simpleCursorAdapter = new SimpleCursorAdapter(getBaseContext(), R.layout.listview_item, cursor, projection, elementIds, 0);
                listView.setAdapter(simpleCursorAdapter);
            } else {
                ((TextView)findViewById(R.id.title)).setText("No Data available to show.");
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * We should acces EmployeeContract constants . but for now i will copy and paste it from there.
     * We can make a jar file EmployeeContract class and share with the app otherwise.
     */
    public Cursor getEmployeeDetails() {
        try {
            //I copied this uri from EmployeeProviderApp.
            Uri employeeUri = Uri.parse("content://com.appsgit.employeeprovider/employee");
            String[] projection = { "_id", "name", "email"}; //you should call _id 

            String selection = "";

            String[] selectionArgs = null;

            String sortOrder = null;

            return getContentResolver().query(employeeUri, projection, selection, selectionArgs, sortOrder);

        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }
    
}

[/code]

 

I have hard coded the Uri string, We should access the EmployeeContract class by making it as a jar file.

[code]

Uri employeeUri = Uri.parse(“content://com.appsgit.employeeprovider/employee”);

[/code]

 

Add the [code]activity_main.xml[/code] file.

 

[code]

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

    <TextView
        android:id="@+id/title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAlignment="center"
        android:text="Employee List From EmployProviderApp"
        android:textSize="20sp"
        android:textStyle="bold"/>
    <ListView
        android:id="@+id/employeeList"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:divider="@color/colorPrimary"/>

</LinearLayout>

[/code]

 

Add the listview_item.xml class res/layout folder.

[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="wrap_content"
    android:orientation="vertical">

    <TextView
        android:id="@+id/name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="5dp"
        />

    <TextView
        android:id="@+id/email"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="5dp"/>

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/colorAccent"
        />
</LinearLayout>

[/code]

 

And the Gradle file is,

 

[code]

apply plugin: 'com.android.application'

android {
    compileSdkVersion 26
    buildToolsVersion "26.0.2"
    defaultConfig {
        applicationId "com.appsgit.managerapp"
        minSdkVersion 20
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:26+'
    testCompile 'junit:junit:4.12'
}

[/code]

 

Now Run the project, You should see the list of Employees.

 

 

 

Now you have created two Projects.

  1. EmployeeProvider App
  2. ManagerApp.

 

Don’t forget to run both of them in the same device/simulator when you are testing.

 

Let me know in the comment section if you have any clarifications.

 

cheers….!

 

Leave a Comment

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