Android Content Provider – Access SQLite database in one application from another application

In this tutorial, we are going to learn how to create Android Content Provider. ”A content provider manages access to a central repository of data. A provider is part of an Android application, which often provides its own UI for working with the data. However, content providers are primarily intended to be used by other applications, which access the provider using a provider client object”.

If you are planning to share your app data with other application, then you have to implement a content provider and export your provider so that other applications will access it and make use of it.

On the other hand, if you data will be private to your application and you have no need to share it with other application, then it is better to use Android SQLite Database. If you want to learn how to implement android SQLite Database in your project I will suggest you read my tutorial on Android SQLite Database Example.

Android has built-in Content Provider like the Dictionary, Calendar Content Provider, Contact Content Provider.

An app can access these built-in Content Provider either directly or through Intent. You can read more about Android Content Provider here.

What we plan to achieve in this example tutorial

We are going to create a custom android content provider which will server a data repository with SQLite database. The Content Provider is exported and its access is restricted with custom permission. Any application that wants to access, create or modify this content provider must implement the permission.

The app will not have its own functionality or user interaction rather its sore function is to serve as a Content Provider.

We will create a second android application, that will implement the permission provided by the first application and will access and manipulate data in the content provider.

If you are interested to learn how to access data from android built-in content provider, I wrote a tutorial on Android Calendar Content Provider API. I will suggest you read this tutorial.

In the second app, we will only implement a features that will help us to access the whole database table or a single row in the table. We can also insert new record in the database.

Creating a Content Uri for a Provider

A provider usually has a single authority, which serves as its Android-internal name. To avoid conflicts with other providers, you should use Internet domain ownership (in reverse) as the basis of your provider authority. Because this recommendation is also true for Android package names, you can define your provider authority as an extension of the name of the package containing the provider.

The providers Authority follows this format – com.inducesmile.androidcontentprovide.provider

To get the path structure, you are going to append the table you want to access to the Authority as shown – com.inducesmile.androidcontentprovide.provider/table_name

To final create a Content Uri, the content:\\ is added to the part as a prefix. The Uri path will look like this – content://com.inducesmile.androidcontentprovide.provider/table_name

In other to get a visual understanding of what we are going to create in this android tutorial, I have add below some screen shots from the application.

SOME SCREENSHOT FROM THE APPLICATION

First App Screenshot

Android content provider

Second App Screenshot

android content provider

CREATE THE FIRST ANDROID PROJECT

Lets start to soil our hands in code. Start up your IDE. For this tutorial, I am using the following tools and environment, feel free to use what works for you.

Windows 10

Android Studio

Sony Xperia ZL

Min SDK 16

Target SDK 25

To create a new android application project, follow the steps as stipulated below.

Go to File menu

Click on New menu

Click on Android Application

Enter Project name: AndroidContentProvider

Package: com.inducesmile.androidcontentprovider

Select Empty Activity

Name your activity: MainActivity

Keep other default selections

Continue to click on next button until Finish button is active, then click on Finish Button.

STRINGS.XML

We are going to update our project strings.xml file located in the values folder inside the res folder. Open the file and add the code below to it.

<string name="app_name">Android Content Provider</string>
<resources>
    <string name="app_name">Android Content Provider</string>
    <string name="display_content">DISPLAY CONTENT</string>
    <string name="usage_instructions">This is Android Content Provider Application that shared its data with other apps. To test or access this data, you must install the second application and use it to query and insert data</string>
    <string name="dictionary_provide_permission">com.inducesmile.androidcontentprovider.DICTIONARY_PROVIDER_PERMISSION</string>
</resources>

COLORS.XML

Open the colors.xml file in the same location as the strings.xml file and add the code below to the file.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>
    <color name="colorBlack">#000000</color>
    <color name="colorWhite">#ffffff</color>
    <color name="colorBg">#3087A8</color>
</resources>

 Create a Contract Class

Here, we will prepare the content Uri for the provider and also use variable names to hold the name of the database, table name, and column names in the table.

Create a Java class file and name it ContractDictionary.java or anything you choose. Open the file and add the code below to it.

import android.net.Uri;
import android.provider.BaseColumns;
public class ContractDictionary {
    public static final String AUTHORITY = "com.inducesmile.androidcontentprovider.Dictionary";
    public static final String PATH  = "/words";
    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + PATH);
    public static final String CONTENT_DICTIONARY_LIST = "vnd.android.cursor.dir/vnd.com.inducesmile.androidcontentprovider.words";
    public static final String CONTENT_DICTIONARY_ITEM = "vnd.android.cursor.item/vnd.com.inducesmile.androidcontentprovider.words";
    public static final String DATABASE_NAME = "dictionary";
    public static final int DATABASE_VERSION = 1;
    public static class Dictionary implements BaseColumns{
        private Dictionary(){}
        public static final String TABLE_NAME = "words";
        public static final String ID = "_id";
        public static final String WORD = "word";
        public static final String MEANING = "meaning";
    }
}

 Create SQLiteOpenHelper Class

Next, to create and manage a database, we will need to create a class that inherits from SQLiteOpenHelper. The class will override the onCreate() and onUpgrade() methods of the SQLiteOpenHelper class.

The two methods are responsibe for creating and updating the android SQLite database.

Create a new Java class file and name it SqliteDatabaseManager.java. Open the file and add the code below to it.

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class SqliteDatabaseManager extends SQLiteOpenHelper{
    public SqliteDatabaseManager(Context context) {
        super(context, ContractDictionary.DATABASE_NAME, null, ContractDictionary.DATABASE_VERSION);
    }
    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        String CREATE_PRODUCTS_TABLE = "CREATE    TABLE " + ContractDictionary.Dictionary.TABLE_NAME + "(" + ContractDictionary.Dictionary.ID + " INTEGER PRIMARY KEY,"
                + ContractDictionary.Dictionary.WORD + " TEXT," + ContractDictionary.Dictionary.MEANING + " TEXT" + ")";
        sqLiteDatabase.execSQL(CREATE_PRODUCTS_TABLE);
    }
    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
        sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + ContractDictionary.Dictionary.TABLE_NAME);
        onCreate(sqLiteDatabase);
    }
}

 Create a Custom Content Provider

Since we have created our SqliteOpenHelper class that will manage the database, we will go further to create a content provider class that will extend the android Content Provider class. The following callback methods are ovverride onCreate(), query(), getType(), insert(), update() and delete().

In the onCreate() callback method, an instance of the SqliteOpenHelper class is created. The getReadableDatabase() and getWritableDatabase() method are call in each callback method as required.

This class makes it possible for other application to access to data store in the SQLite database in this application.

When we create the second application, we will learn how to get access and play around with the SQLite database.

Now, create new Java class file like before and name it DictionaryProvider.java. Open the class and add the code below.

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.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.widget.Toast;
public class DictionaryProvider extends ContentProvider{
    private SqliteDatabaseManager dbManager;
    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    static {
        sUriMatcher.addURI(ContractDictionary.AUTHORITY, ContractDictionary.PATH, 1);
        sUriMatcher.addURI(ContractDictionary.AUTHORITY, ContractDictionary.PATH + "/#", 2);
    }
    @Override
    public boolean onCreate() {
        dbManager = new SqliteDatabaseManager(getContext());
        return false;
    }
    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, String[] projections, String selection, String[] selectionArgs, String sortOrder) {
        SQLiteDatabase db = dbManager.getWritableDatabase();
        Cursor mCursor = null;
        switch (sUriMatcher.match(uri)){
            case 1:
                mCursor = db.query(ContractDictionary.Dictionary.TABLE_NAME, projections, selection, selectionArgs, null, null, null);
                break;
            case 2:
                selection = selection + ContractDictionary.Dictionary.ID + " = " + uri.getLastPathSegment();
                mCursor = db.query(ContractDictionary.Dictionary.TABLE_NAME, projections, selection, selectionArgs, null, null, null);
                break;
            default:
                Toast.makeText(getContext(), "Invalid content uri", Toast.LENGTH_LONG).show();
                throw new IllegalArgumentException("Unknown Uri: " + uri);
        }
        mCursor.setNotificationUri(getContext().getContentResolver(), uri);
        return mCursor;
    }
    @Nullable
    @Override
    public String getType(Uri uri) {
        switch (sUriMatcher.match(uri)){
            case 1:
                return ContractDictionary.CONTENT_DICTIONARY_LIST;
            case 2:
                return ContractDictionary.CONTENT_DICTIONARY_ITEM;
            default:
                throw new IllegalArgumentException("Unknown Uri: " + uri);
        }
    }
    @Nullable
    @Override
    public Uri insert(Uri uri, ContentValues contentValues) {
        SQLiteDatabase db = dbManager.getWritableDatabase();
        if(sUriMatcher.match(uri) != 1) {
            throw new IllegalArgumentException("Unknown URI: " + uri);
        }
        long rowId = db.insert(ContractDictionary.Dictionary.TABLE_NAME, null, contentValues);
        if(rowId > 0) {
            Uri articleUri = ContentUris.withAppendedId(ContractDictionary.CONTENT_URI, rowId);
            getContext().getContentResolver().notifyChange(articleUri, null);
            return articleUri;
        }
        throw new IllegalArgumentException("Unknown URI: " + uri);
    }
    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        SQLiteDatabase db = dbManager.getWritableDatabase();
        int count = 0;
        switch(sUriMatcher.match(uri)) {
            case 1:
                count = db.delete(ContractDictionary.Dictionary.TABLE_NAME, selection, selectionArgs);
                break;
            case 2:
                String rowId = uri.getPathSegments().get(1);
                count = db.delete(ContractDictionary.Dictionary.TABLE_NAME, ContractDictionary.Dictionary.ID + " = " + rowId
                        + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ")" : ""), selectionArgs);
                break;
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    }
    @Override
    public int update(Uri uri, ContentValues contentValues, String selection, String[] selectionArgs) {
        SQLiteDatabase db = dbManager.getWritableDatabase();
        int count = 0;
        switch (sUriMatcher.match(uri)){
            case 1:
                count = db.update(ContractDictionary.Dictionary.TABLE_NAME, contentValues, selection, selectionArgs);
                break;
            case 2:
                String rowId = uri.getPathSegments().get(1);
                count = db.update(ContractDictionary.Dictionary.TABLE_NAME, contentValues, ContractDictionary.Dictionary.ID + " = " + rowId +
                                (!TextUtils.isEmpty(selection) ? " AND (" + ")" : ""), selectionArgs);
                break;
            default:
                throw new IllegalArgumentException("Unknown Uri: " + uri );
        }
        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    }
}

 Update AndroidManifest.xml

Since a provider is part of android component, we are going to add the provider element in the application section in AndroidManifest.xml.

The provider element has a name and authorities attribute which we will specify. We will also add the android:exported=”true” which will make the content provider available to other applications.

Finally, the permission that any application that want to access this content provider will implement before it gets access to it is also specified.

The update version of the AndroidManifest.xml file is shown below.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.inducesmile.androidcontentprovider">
    <permission android:name="com.inducesmile.androidcontentprovider.DICTIONARY_PROVIDER_PERMISSION" android:protectionLevel="normal" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        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.inducesmile.androidcontentprovider.Dictionary"
            android:name="com.inducesmile.androidcontentprovider.DictionaryProvider"
            android:exported="true"/>
    </application>
</manifest>

 MainActivity class and its layout file

Since this application only expose its content provider to other application to use, we are not going to implement any user interface apart from adding a TextView widget in the layout file with the instruction.

activity_main.xml

<?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:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:background="@color/colorBg"
    tools:context="com.inducesmile.androidcontentprovider.MainActivity">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@color/colorWhite"
        android:textSize="15sp"
        android:text="@string/usage_instructions"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"/>
    
</RelativeLayout>

 MainActivity class

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = MainActivity.class.getSimpleName();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

 Create another android app that will access data the Content Provider App

To create a new android application project, follow the steps as stipulated below.

Go to File menu

Click on New menu

Click on Android Application

Enter Project name: AndroidAccessContentProvider

Package: com.inducesmile.androidaccesscontentprovider

Select Empty Activity

Name your activity: MainActivity

Keep other default selections

Continue to click on next button until Finish button is active, then click on Finish Button.

ADD LIBRARY DEPENDENCIES IN BUILD.GRADLE

We are going to update the module build.gradle file since we are going to add some dependency libraries that the application will make use of.

The update version of the build.gradle is shown below.

apply plugin: 'com.android.application'
android {
    compileSdkVersion 25
    buildToolsVersion "24.0.1"
    defaultConfig {
        applicationId "com.inducesmile.accesscontentprovider"
        minSdkVersion 16
        targetSdkVersion 25
        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:25.0.1'
    compile 'com.android.support:design:25.0.1'
    compile 'com.android.support:cardview-v7:25.0.1'
    compile 'com.android.support:recyclerview-v7:25.0.1'
    compile 'com.android.support:support-v4:25.0.1'
    testCompile 'junit:junit:4.12'
}

 STRINGS.XML

We are going to update our project strings.xml file located in the values folder inside the res folder. Open the file and add the code below to it.

<resources>
    <string name="app_name">Access Content Provider</string>
    <string name="display_dictoinary_provider_words">DISPLAY DICTOINARY PROVIDER WORDS</string>
    <string name="add_new_provider_content">ADD NEW PROVIDER CONTENT</string>
    <string name="honesty">Honesty</string>
    <string name="enter_word">Enter word</string>
    <string name="enter_meaning">Enter meaning</string>
    <string name="add_dictionary_word">ADD DICTIONARY WORD</string>
    <string name="add_to">Add to Content Provider</string>
</resources>

COLORS.XML

Open the colors.xml file in the same location as the strings.xml file and add the code below to the file.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#B8861C</color>
    <color name="colorPrimaryDark">#a37617</color>
    <color name="colorAccent">#B8651C</color>
    <color name="colorBg">#F3A968</color>
    <color name="colorBlack">#000000</color>
    <color name="colorWhite">#ffffff</color>
    <color name="colorBorder">#dbd9d9</color>
</resources>

 SplashActivity class and its layout file

This is the launch activity which a user will see once the app loads. Since we stated that we will only implement methods to query the dictionary content provider and also insert data to it, we will add two Button widgets to the layout file.

activity_splash.xml

Open this layout file and add two button widgets. These button widgets will be wired in the activity class once the instances are obtained.

Open the layout file and add the code below.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_splash"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:background="@color/colorBg"
    tools:context="com.inducesmile.accesscontentprovider.SplashActivity">
    <Button
        android:id="@+id/dispaly_content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorAccent"
        android:textColor="@color/colorWhite"
        android:text="@string/display_dictoinary_provider_words"
        android:padding="20dp"/>
    <Button
        android:id="@+id/add_new_content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorAccent"
        android:textColor="@color/colorWhite"
        android:layout_marginTop="16dp"
        android:text="@string/add_new_provider_content"
        android:padding="20dp"/>
    
</LinearLayout>

 SplashActivity class

The instances of the button widgets are obtained and wired with on click event listener. Open the file and add the code below to the file.

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class SplashActivity extends AppCompatActivity {
    private static final String TAG = SplashActivity.class.getSimpleName();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_splash);
        Button displayContentButton = (Button)findViewById(R.id.dispaly_content);
        displayContentButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent displayIntent = new Intent(SplashActivity.this, DisplayContentActivity.class);
                startActivity(displayIntent);
            }
        });
        Button addContentButton = (Button)findViewById(R.id.add_new_content);
        addContentButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent addIntent = new Intent(SplashActivity.this, AddContentActivity.class);
                startActivity(addIntent);
            }
        });
    }
}

 Add Data to the Content Provider

To add a row data in the Content Provider, we will create EditText widgets and Button widget that will be used to submit filled input box.

Create a new Empty Activity class with its layout file.

activity_add_content.xml

In this layout file add 2 EditText widgets and a Button Widgets. The complete code for this layout file is shown below.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_add_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.inducesmile.accesscontentprovider.AddContentActivity">
    <EditText
        android:id="@+id/enter_word"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/enter_word"
        android:textColorHint="@color/colorBorder"
        android:textSize="14sp"
        android:inputType="text"
        android:background="@drawable/brown_border"
        android:maxLines="1"
        android:layout_marginRight="12dp"
        android:layout_marginEnd="12dp"
        android:textColor="@color/colorBlack"
        android:padding="16dp"/>
    <EditText
        android:id="@+id/enter_meaning"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/enter_meaning"
        android:textColorHint="@color/colorBorder"
        android:textSize="14sp"
        android:inputType="text"
        android:background="@drawable/brown_border"
        android:maxLines="1"
        android:layout_marginTop="18dp"
        android:layout_marginRight="12dp"
        android:layout_marginEnd="12dp"
        android:textColor="@color/colorBlack"
        android:padding="16dp"/>
    <Button
        android:id="@+id/add_content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorAccent"
        android:textColor="@color/colorWhite"
        android:layout_marginTop="24dp"
        android:text="@string/add_dictionary_word"
        android:padding="20dp"/>
</LinearLayout>

 AddContentActivity Class

The instances of the View controls in the layout file is obtained in this activity class. When the button is clicked the user input values in the Edittext fields are obtained.

These values are store in a ContentValues object and it is then pass as a parameter to the insert() method of the ContentResolver class.

Open the activity class and add the code below.

import android.content.ContentValues;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class AddContentActivity extends AppCompatActivity {
    private static final String TAG = AddContentActivity.class.getSimpleName();
    private EditText wordInput, meaningInput;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_add_content);
        setTitle(getString(R.string.add_to));
        wordInput = (EditText)findViewById(R.id.enter_word);
        meaningInput = (EditText)findViewById(R.id.enter_meaning);
        Button addContentButton = (Button)findViewById(R.id.add_content);
        addContentButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String word = wordInput.getText().toString();
                String meaning = meaningInput.getText().toString();
                if(TextUtils.isEmpty(word) || TextUtils.isEmpty(meaning)){
                    Toast.makeText(AddContentActivity.this, "All input fields must be filled", Toast.LENGTH_LONG).show();
                }else{
                    String AUTHORITY = "com.inducesmile.androidcontentprovider.Dictionary";
                    String PATH  = "/words";
                    Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + PATH);
                    ContentValues values = new ContentValues();
                    values.put("word", word);
                    values.put("meaning", meaning);
                    Uri mUri = getContentResolver().insert(CONTENT_URI, values);
                    if(mUri != null){
                        Toast.makeText(AddContentActivity.this, "Successfully added to Content Provider", Toast.LENGTH_LONG).show();
                    }
                }
            }
        });
    }
}

 Retrieve all stored column data in the Content Provider

To retrieve some columns or all the data from the Content Provider app, you can use the Content Uri with the query() method of the ContentResolver class.

Since we are going to display rows of data, We are going to use a RecyclerView with an Adapter which will bind the data source to items of the Recyclerview.

activity_display_content.xml

Add a RecyclerView widget in this layer file. The complete source code is as shown.

<?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:id="@+id/activity_display_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.inducesmile.accesscontentprovider.DisplayContentActivity">
    <android.support.v7.widget.RecyclerView
        android:id="@+id/list_dictionary"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingBottom="12dp"
        android:scrollbars="none" />
</RelativeLayout>

 DisplayContentActivity Class

Get the instance of the RecyclerView. Set a linear layout manager to it. Prepare the adapter instance and pass it as a parameter to the RecyclerView object.

We use the query() method of the ContentResolver class to return a cursor object. We loop through the cursor to obtain the data we need to bind in the adapter class.

Open this file and add the code below to it.

import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class DisplayContentActivity extends AppCompatActivity {
    private static final String TAG = DisplayContentActivity.class.getSimpleName();
    public static final String AUTHORITY = "com.inducesmile.androidcontentprovider.Dictionary";
    public static final String PATH  = "/words";
    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + PATH);
    private RecyclerView recyclerView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_display_content);
        recyclerView = (RecyclerView)findViewById(R.id.list_dictionary);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(linearLayoutManager);
        recyclerView.setHasFixedSize(true);
        Cursor mCursor = getContentResolver().query(CONTENT_URI, null, null, null, null, null);
        List<String> words = new ArrayList<>();
        if(mCursor.moveToFirst()){
            do{
                String word = mCursor.getString(1);
                words.add(word);
            }while(mCursor.moveToNext());
            DictionaryAdapter mAdapter = new DictionaryAdapter(DisplayContentActivity.this, words);
            recyclerView.setAdapter(mAdapter);
        }else{
            Toast.makeText(DisplayContentActivity.this, "Nothing is inside the cursor ", Toast.LENGTH_LONG).show();
        }
        mCursor.close();
    }
}

 RecyclerView Adapter and ViewHolder Classes

The RecyclerView makes use of an Adapter and a ViewHolder classes. The Adapter class in turn inflates a layout file which represents each data item of the RecyclerView.

Create the below class and add the code associated with each of them.

DictionaryAdapter Class

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.List;
public class DictionaryAdapter extends RecyclerView.Adapter<DictionaryViewHolder>{
    private Context context;
    private List<String> wordList;
    public DictionaryAdapter(Context context, List<String> wordList) {
        this.context = context;
        this.wordList = wordList;
    }
    @Override
    public DictionaryViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.word_list_layout, parent, false);
        return new DictionaryViewHolder(view);
    }
    @Override
    public void onBindViewHolder(DictionaryViewHolder holder, int position) {
        String rowContent = wordList.get(position);
        holder.word.setText(rowContent);
    }
    @Override
    public int getItemCount() {
        return wordList.size();
    }
}

 DictionaryViewHolder Class

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.TextView;
public class DictionaryViewHolder extends RecyclerView.ViewHolder{
    public TextView word;
    public DictionaryViewHolder(View itemView) {
        super(itemView);
        word = (TextView)itemView.findViewById(R.id.word);
    }
}

word_list_layout.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="wrap_content"
    android:orientation="vertical"
    android:padding="8dp">
    <TextView
        android:id="@+id/word"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/honesty"
        android:padding="8dp"
        android:textSize="15sp"/>
    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:layout_marginTop="8dp"
        android:background="@color/colorBorder"/>
</LinearLayout>

This brings us to the end of this tutorial. I hope that you have learn something. Run your app and see for yourself.

You can download the code for this tutorial below. If you are having hard time downloading the tutorial, kindly contact me.

Remember to subscribe with your email address to be among the first to receive my new android blog post once it is published.

 

OTHER INTERESTING POSTS:

Add a Comment