Android Content Provider Example using SQLite Database

ContentProvider

A ContentProvider provides data from one application to another, when requested. It manages access to a structured set of data. It provides mechanisms for defining data security(i.e. by enforcing read/write permissions)ContentProvider offer a standard interface that connects data in one process with code running in another process.

When an application wants to access the data of a ContentProvider, it makes a request. These requests are handled by the ContentResolver object, which communicates with the ContentProvider as a client. The provider object receives data requests from clients, performs the requested action, and returns the results in cursor format.

In this tutorial, I will create two apps MyContacts App and ContactList App and I will demonstrate you how ContactList App will use the  MyContact App’s data (stored in SQLite database ) using contentProvider.

Get GITHUB code from Here.

Creating a New Project

1. Create a new project  named MyContacts in Android Studio from FileNew Project by filling the required details. When it prompts you to select the activity, choose Empty Activity and continue.

2. Open build.gradle located in app level and add the following dependency.

build.gradle

dependencies {
   
    compile 'com.android.support:design:27.1.1'
    
    //recyclerView
    implementation 'com.android.support:recyclerview-v7:27.0.2'
   
}

Create SQLite Database for MyContacts App

3. Create a new Java class DBOpenHelper and add the following code. This is our DBHelper class, here we are creating the Contacts Database.

DBOpenHelper.Java

package com.c1ctech.mycontacts;

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

public class DBOpenHelper extends SQLiteOpenHelper {

    //Constants for db name and version
    private static final String DATABASE_NAME = "contacts.db";
    private static final int DATABASE_VERSION = 1;

    //Constants for table and columns
    public static final String TABLE_CONTACTS = "contacts";
    public static final String CONTACT_ID = "_id";
    public static final String CONTACT_NAME = "contactName";
    public static final String CONTACT_PHONE = "contactPhone";
    public static final String CONTACT_CREATED_ON = "contactCreationTimeStamp";

    public static final String[] ALL_COLUMNS =
            {CONTACT_ID, CONTACT_NAME, CONTACT_PHONE, CONTACT_CREATED_ON};

    //Create Table
    private static final String CREATE_TABLE =
            "CREATE TABLE " + TABLE_CONTACTS + " (" +
                    CONTACT_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
                    CONTACT_NAME + " TEXT, " +
                    CONTACT_PHONE + " TEXT, " +
                    CONTACT_CREATED_ON + " TEXT default CURRENT_TIMESTAMP" +
                    ")";

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

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

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
        sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + TABLE_CONTACTS);
        onCreate(sqLiteDatabase);
    }
}

Create Custom Android Content Provider

4. Create a new Java class named ContactsProvider and make it as subclass of ContentProvider and add the below code.

Creating ContentUri

ContactsProvider is a subclass of ContentProvider and in order to identify the data in the provider we use Content URIs. A Content URI  has the following format:

content://<authority>/<path>/<id>
content:// : Standard prefix indicating the data is controlled by content provider.
Authority : Uniquely identify the particular content provider(package name).
path : Used to determine the type of data(table or file) being requested.
id : specifies which record(row) is being requested.(optional).
private static final String AUTHORITY = "com.c1ctech.mycontacts";
private static final String BASE_PATH = "contacts";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH);

Creating UriMatcher

Remember the ContentResolver is not aware of the internal implementation of our Content Provider class, so whenever we receive a call from the ContentResolver we have to perform an internal check to see if the call was for a the whole table or for a single row in the table.

The way we determine if the call is for a specific row on the table is if the calls contains any qualifier after the table name such as /authority/path/table/2 and if the calls is the format of say  /authority/path/table then we know it is a query for the table.

the provider API includes the convenience class UriMatcher, which maps content URI “patterns” to integer values. Add the following code to your class , the “#” represents any number after the table indicating a table row.

private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

static {
    uriMatcher.addURI(AUTHORITY, BASE_PATH, CONTACTS);
    uriMatcher.addURI(AUTHORITY, BASE_PATH + "/#", CONTACT_ID);
}

Override ContentProvider’s Methods

Here is the list of methods which you need to override in ContentProvider class to have your ContentProvider working.All of these methods except onCreate() are called by a client application that is attempting to access your content provider:

  • onCreate() method is called when the provider is started.
  • query() method retrieves data from your provider.The result is returned as a Cursor object.
  • insert() method inserts a new record into the content provider.Return a content URI for the newly-inserted row.
  • delete() method deletes an existing record from the content provider.Return the number of rows deleted.
  • update() method updates an existing record from the content provider.Return the number of rows updated.
  • getType() method returns the MIME type corresponding to a content URI.

ContactsProvider.Java

package com.c1ctech.mycontacts;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.support.annotation.Nullable;

public class ContactsProvider extends ContentProvider {

    private static final String AUTHORITY = "com.c1ctech.mycontacts";
    private static final String BASE_PATH = "contacts";
    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH);

    private static final int CONTACTS = 1;
    private static final int CONTACT_ID = 2;

    private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

    static {
        uriMatcher.addURI(AUTHORITY, BASE_PATH, CONTACTS);
        uriMatcher.addURI(AUTHORITY, BASE_PATH + "/#", CONTACT_ID);
    }

    private SQLiteDatabase database;

    @Override
    public boolean onCreate() {
        DBOpenHelper helper = new DBOpenHelper(getContext());
        database = helper.getWritableDatabase();
        return true;
    }

    @Nullable
    @Override
    public Cursor query(Uri uri, String[] strings, String s, String[] strings1, String s1) {
        Cursor cursor;
        switch (uriMatcher.match(uri)) {
            case CONTACTS:
                cursor = database.query(DBOpenHelper.TABLE_CONTACTS, DBOpenHelper.ALL_COLUMNS,
                        s, null, null, null, DBOpenHelper.CONTACT_NAME + " ASC");


                break;
            default:
                throw new IllegalArgumentException("This is an Unknown URI " + uri);
        }
        cursor.setNotificationUri(getContext().getContentResolver(), uri);

        return cursor;
    }

    @Nullable
    @Override
    public String getType(Uri uri) {

        switch (uriMatcher.match(uri)) {
            case CONTACTS:
                return "vnd.android.cursor.dir/contacts";
            default:
                throw new IllegalArgumentException("This is an Unknown URI " + uri);
        }
    }

    @Nullable
    @Override
    public Uri insert(Uri uri, ContentValues contentValues) {
        long id = database.insert(DBOpenHelper.TABLE_CONTACTS, null, contentValues);

        if (id > 0) {
            Uri _uri = ContentUris.withAppendedId(CONTENT_URI, id);
            getContext().getContentResolver().notifyChange(_uri, null);

            return _uri;
        }
        throw new SQLException("Insertion Failed for URI :" + uri);

    }

    @Override
    public int delete(Uri uri, String s, String[] strings) {
        int delCount = 0;
        switch (uriMatcher.match(uri)) {
            case CONTACTS:
                delCount = database.delete(DBOpenHelper.TABLE_CONTACTS, s, strings);
                break;
            default:
                throw new IllegalArgumentException("This is an Unknown URI " + uri);
        }
        getContext().getContentResolver().notifyChange(uri, null);
        return delCount;
    }

    @Override
    public int update(Uri uri, ContentValues contentValues, String s, String[] strings) {
        int updCount = 0;
        switch (uriMatcher.match(uri)) {
            case CONTACTS:
                updCount = database.update(DBOpenHelper.TABLE_CONTACTS, contentValues, s, strings);
                break;
            default:
                throw new IllegalArgumentException("This is an Unknown URI " + uri);
        }
        getContext().getContentResolver().notifyChange(uri, null);
        return updCount;
    }
}

Register the Content Provider

5. We need to provide an entry for our custom Android Content Provider in the AndroidManifest.xml

Open your AndroidManifest.xml and add the permissions and provider entry as in the following code.

we need to provide the authority and read and write permissions here.
using android:exported=”true” our provider becomes available to other applications.

AndroidManifest.xml

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

    <permission android:name="com.c1ctech.mycontacts.READ_DATABASE" android:protectionLevel="normal" />
    <permission android:name="com.c1ctech.mycontacts.WRITE_DATABASE" android:protectionLevel="normal" />

    <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>

    <provider
        android:authorities="com.c1ctech.mycontacts"
        android:name=".ContactsProvider"
        android:exported="true"
        android:readPermission="com.c1ctech.mycontacts.READ_DATABASE"
        android:writePermission="com.c1ctech.mycontacts.WRITE_DATABASE"
        />
    </application>
</manifest>

Creating Layouts

6. Open activity_main and write the below code.It contains one recyclerView and one floatingActionButton(ic_input_add) for adding contacts in recyclerview.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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=".MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />


    </android.support.design.widget.AppBarLayout>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.v7.widget.RecyclerView
            android:layout_marginTop="70dp"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/contact_list"/>

    </RelativeLayout>

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="16dp"
        app:srcCompat="@android:drawable/ic_input_add" />

</android.support.design.widget.CoordinatorLayout>

7. Create a new layout dialog_contact_details and write the below code.It represents the layout set for an Alertdialog.

dialog_contact_details.xml

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

    <TextView
        android:id="@+id/text_view_emp_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="@string/enter_contact_details"
        android:textSize="20sp"
        android:textStyle="bold" />

    <EditText
        android:id="@+id/editTextDialogNameInput"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/enterName" />


    <EditText
        android:id="@+id/editTextDialogPhoneInput"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/enterPhoneNumber" />

</LinearLayout>

8. Under res->menu folder create a new menu resource file main_menu and write the below code.It contains one item deleteAllContacts used to delete all contacts stored in provider.

main_menu.xml

<menu 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"
    tools:context="com.androidtutorialpoint.mycontacts.MainActivity">
    <item
        android:id="@+id/deleteAllContacts"
        android:orderInCategory="100"
        android:title="@string/delete_all_contacts"
        app:showAsAction="never" />
</menu>

Creating Adapter For RecyclerView

9. Create a model class Contact in your root folder(com.c1ctech.mycontacts) used while working with recyclerView.

Contact.Java

package com.c1ctech.mycontacts;

public class Contact {

    private String contact_name;
    private String contact_phone;

    public Contact(String contact_name, String contact_phone) {
        this.contact_name = contact_name;
        this.contact_phone = contact_phone;
    }

    public String getContact_name() {
        return contact_name;
    }

    public void setContact_name(String contact_name) {
        this.contact_name = contact_name;
    }

    public String getContact_phone() {
        return contact_phone;
    }

    public void setContact_phone(String contact_phone) {
        this.contact_phone = contact_phone;
    }
}

10. Create a new layout contact_list_item and write the below code.It represents the layout of a single item of a recyclerview .

contact_list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center_vertical"
    android:padding="4dp">

    <ImageView
        android:id="@+id/imageDocIcon"
        android:layout_width="72dp"
        android:layout_height="72dp"
        android:src="@drawable/profile_pic" />

    <TextView
        android:id="@+id/nameTextView"
        android:layout_width="wrap_content"
        android:layout_height="36dp"
        android:layout_alignParentEnd="true"
        android:layout_alignParentRight="true"
        android:layout_marginLeft="15dp"
        android:layout_marginTop="5dp"
        android:layout_toEndOf="@+id/imageDocIcon"
        android:layout_toRightOf="@+id/imageDocIcon"
        android:text="Dummy Text"
        android:textColor="@android:color/black"
        android:textSize="20sp"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/phoneTextView"
        android:layout_width="match_parent"
        android:layout_height="36dp"
        android:layout_alignParentEnd="true"
        android:layout_alignParentRight="true"
        android:layout_below="@+id/nameTextView"
        android:layout_marginLeft="15dp"
        android:layout_toEndOf="@+id/imageDocIcon"
        android:layout_toRightOf="@+id/imageDocIcon"
        android:text="Dummy Text"
        android:textColor="@android:color/black"
        android:textSize="15sp" />

</RelativeLayout>

11. Create a class named ContactsAdapter and write the below code.Its object is used to set as adapter in recyclerView.

ContactsAdapter.Java

package com.c1ctech.mycontacts;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import android.widget.TextView;

import java.util.List;

public class ContactsAdapter extends RecyclerView.Adapter<ContactsAdapter.ViewHolder> {


    Context mContext;
    private List<Contact> items;

    public ContactsAdapter(Context mContext, List<Contact> items) {
        this.mContext = mContext;
        this.items = items;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(mContext).inflate(R.layout.contact_list_item, parent, false);
        return new ViewHolder(v);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Contact item = items.get(position);
        holder.phone_no.setText(item.getContact_phone());
        holder.name.setText(item.getContact_name());

    }

    @Override
    public int getItemCount() {
        return items.size();
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        public TextView name;
        public TextView phone_no;

        public ViewHolder(View itemView) {
            super(itemView);
            name = (TextView) itemView.findViewById(R.id.nameTextView);
            phone_no = (TextView) itemView.findViewById(R.id.phoneTextView);
        }
    }
}

12. Now open MainActivity and write the below code.

MainActivity.Java

package com.c1ctech.mycontacts;

import android.app.LoaderManager;
import android.content.ContentValues;
import android.content.CursorLoader;
import android.content.DialogInterface;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

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

    ContactsAdapter adapter;
    RecyclerView rv_list;

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


        rv_list = (RecyclerView) findViewById(R.id.contact_list);
        rv_list.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
        rv_list.setLayoutManager(new LinearLayoutManager(this));

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getLoaderManager().initLoader(0, null, this);
        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                LayoutInflater li = LayoutInflater.from(MainActivity.this);
                View getEmpIdView = li.inflate(R.layout.dialog_contact_details, null);

                AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(MainActivity.this);

                // set dialog_contact_details.xmll to alertdialog builder
                alertDialogBuilder.setView(getEmpIdView);

                final EditText nameInput = (EditText) getEmpIdView.findViewById(R.id.editTextDialogNameInput);
                final EditText phoneInput = (EditText) getEmpIdView.findViewById(R.id.editTextDialogPhoneInput);
                // set dialog message

                alertDialogBuilder
                        .setCancelable(false)
                        .setPositiveButton("Add", new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int id) {
                                // get user input and set it to result
                                // edit text
                                insertContact(nameInput.getText().toString(), phoneInput.getText().toString());
                                restartLoader();

                            }
                        }).create()
                        .show();

            }
        });
    }


    private void insertContact(String contactName, String contactPhone) {
        ContentValues values = new ContentValues();
        values.put(DBOpenHelper.CONTACT_NAME, contactName);
        values.put(DBOpenHelper.CONTACT_PHONE, contactPhone);
        Uri contactUri = getContentResolver().insert(ContactsProvider.CONTENT_URI, values);
        Toast.makeText(this, "Created Contact " + contactName, Toast.LENGTH_LONG).show();
    }

    private void deleteAllContacts() {

        getContentResolver().delete(ContactsProvider.CONTENT_URI, null, null);
        restartLoader();
        Toast.makeText(this, "All Contacts Deleted", Toast.LENGTH_LONG).show();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        
        switch (item.getItemId()) {
            case R.id.deleteAllContacts:
                deleteAllContacts();
                return true;
        }

        return super.onOptionsItemSelected(item);
    }

    private void restartLoader() {
        getLoaderManager().restartLoader(0, null, this);
    }


    @Override
    public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
        return new CursorLoader(this, ContactsProvider.CONTENT_URI, null, null, null, null);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {

        List<Contact> list = new ArrayList<>();

        while (cursor.moveToNext()) {
            int index1 = cursor.getColumnIndex(DBOpenHelper.CONTACT_NAME);
            int index2 = cursor.getColumnIndex(DBOpenHelper.CONTACT_PHONE);
            String name = cursor.getString(index1);
            String phone_no = cursor.getString(index2);

            Contact contact = new Contact(name, phone_no);
            list.add(contact);
        }

        adapter = new ContactsAdapter(this, list);
        rv_list.setAdapter(adapter);

    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {

    }

}

In the MainActivity.java we are implementing the LoaderManager.LoaderCallbacks interface to work with loader.

In the onCreate() method on clicking the FloatingActionButton we are invoking an AlertDialog to input the Contact’s Name and Phone number.

On clicking the Add button of the Dialog, insertContact()  method is called, which uses the insert() method of our custom Android Content Provider to insert a new record into the database.

Similarly, we have an option in the Menu to delete all the existing contacts by calling the delete() method of our custom Android Content Provider .

Next, we have implemented the methods for the LoaderManager.LoaderCallbacks interface

  1. restartLoader(int id, Bundle args, LoaderCallbacks callback) : It restarts an existing Loader with the particular id.
  2. onCreateLoader(int id, Bundle args) : whenever we initialize loader using the initLoader like this:
    getLoaderManager().initLoader(0, null, this);

    This methods get automatically triggered ,runs in a separate thread,loads the data from the provider and return a new Loader for the given id .

  3. onLoadFinished(Loader loader, Cursor cursor) : This method is Called when a previously created loader has finished its load.It runs in main thread .@param loader indicates the Loader that has finished and @param cursor indicates the data generated by the Loader.
  4. onLoaderReset(Loader loader) : This method is called when a previously created loader is being reset, and thus making its data unavailable.

Now run the app and add few contacts. It should create a list sorted by the Name in the alphabetical order like this.

Creating the ContactList App(consumer app)   

13. Now we will create another app ContactList in the same way we have created the MyContacts App earliar.

To retrieve data from a provider, follow these basic steps:

  1. Request the read access permission for the provider.
  2. Define the code that sends a query to the provider.

Request the read access permission for the provider

Add the following permissions to use the ContactsProvider in the AndroidManifest.xml

<uses-permission android:name="com.c1ctech.mycontacts.READ_DATABASE" />
<uses-permission android:name="com.c1ctech.mycontacts.WRITE_DATABASE" />

Define the code that sends a query to the provider

private static final String AUTHORITY = "com.c1ctech.mycontacts";
private static final String BASE_PATH = "contacts";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH);

@Override
public Loader<Cursor> onCreateLoader(int id, Bundle bundle) {
//loads data from the content provider
    if (id == 0) {
        return new CursorLoader(this, CONTENT_URI, null, null, null, null);
    }
    return null;

}

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
//Getting data from MyContacts App as cursor object
    List<Contact> list = new ArrayList<>();
//Adding cursor data in a list
    while (cursor.moveToNext()) {

        String name = cursor.getString(1);
        String phone_no = cursor.getString(2);

        Contact contact = new Contact(name, phone_no);
        list.add(contact);
    }
//passing list to adapter which will display the list items in recyclerView
    adapter = new ContactsAdapter(this, list);
    rv_list.setAdapter(adapter);


}

14. Open activity_main.xml and write the below code.It is similar to the layout of MyContacts except in place of FloatingAction Button with property app:srcCompat=”@android:drawable/ic_input_add” we use app:srcCompat=”@android:drawable/ic_popup_sync”.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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=".MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />


    </android.support.design.widget.AppBarLayout>


    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.v7.widget.RecyclerView

            android:id="@+id/contact_list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="70dp"

            />

    </RelativeLayout>

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="16dp"
        app:srcCompat="@android:drawable/ic_popup_sync" />

</android.support.design.widget.CoordinatorLayout>

15. Open MainActivity.Java and write following code.The code for MainActivity is pretty much same as the MyContacts app, We have just removed the code for inserting and deleting the Contacts and we are just displaying those records.
MainActivity.Java 

package com.c1ctech.contactlist;

import android.app.LoaderManager;
import android.content.CursorLoader;
import android.content.Loader;
import android.content.UriMatcher;
import android.database.Cursor;
import android.net.Uri;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.View;


import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor>, View.OnClickListener {

    ContactsAdapter adapter;
    RecyclerView rv_list;
    FloatingActionButton fab;

    private static final String AUTHORITY = "com.c1ctech.mycontacts";
    private static final String BASE_PATH = "contacts";
    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH);

    // Constant to identify the requested operation
    private static final int CONTACTS = 1;
    private static final int CONTACT_ID = 2;

    private boolean firstTimeLoaded = false;


    private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

    static {
        uriMatcher.addURI(AUTHORITY, BASE_PATH, CONTACTS);
        uriMatcher.addURI(AUTHORITY, BASE_PATH + "/#", CONTACT_ID);
    }

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

        rv_list = (RecyclerView) findViewById(R.id.contact_list);

        rv_list.setLayoutManager(new LinearLayoutManager(this));
        rv_list.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(this);
    }


    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle bundle) {
        if (id == 0) {
            return new CursorLoader(this, CONTENT_URI, null, null, null, null);
        }
        return null;

    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {

        List<Contact> list = new ArrayList<>();

        while (cursor.moveToNext()) {

            String name = cursor.getString(1);
            String phone_no = cursor.getString(2);

            Contact contact = new Contact(name, phone_no);
            list.add(contact);
        }

        adapter = new ContactsAdapter(this, list);
        rv_list.setAdapter(adapter);

    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
       
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.fab:
                if (firstTimeLoaded == false) {
                    getLoaderManager().initLoader(0, null, this);
                    firstTimeLoaded = true;
                } else {
                    getLoaderManager().restartLoader(0, null, this);
                }

                break;
            default:
                break;
        }

    }
}

When you run ContactList App ,you find refresh button ,when you click on it you get all the contacts stored in MyContacts App like this:

 

I hope this tutorial will help you in understanding how to work with contentProvider in sharing data from one application to another.

 

Leave a Reply