Welcome to my Android Content Provider tutorial. I’ve received many questions about this topic. I have received many questions specifically about how to access a Content Provider from another application. So here I’ll make to apps. One will function as the Content Provider and the other will access data using a Content Resolver.
I haven’t found a tutorial online that explains how easy it is to use Content Resolvers in this way, so I hope this video is very useful. All of the code follows the video below and it is heavily commented.
If you find videos like this to be useful, it helps to tell Google Plus with a click here [googleplusone]
Code From the Video
Contact Provider Code
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.newthinktank.derekbanas.contactprovider" >
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- The Content Provider is declared -->
<provider
android:name=".ContactProvider"
android:authorities="com.newthinktank.derekbanas.contactprovider.ContactProvider"
android:exported="true"
android:multiprocess="true" >
</provider>
</application>
</manifest>
ContactProvider.java
package com.newthinktank.derekbanas.contactprovider;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.widget.Toast;
import java.util.HashMap;
// Contact Providers allow applications to share data using an API
// The interface provides access using delete, insert, query and update methods
public class ContactProvider extends ContentProvider{
// The Java namespace for the Content Provider
static final String PROVIDER_NAME = "com.newthinktank.derekbanas.contactprovider.ContactProvider";
// Assigned to a content provider so any application can access it
// cpcontacts is the virtual directory in the provider
static final String URL = "content://" + PROVIDER_NAME + "/cpcontacts";
static final Uri CONTENT_URL = Uri.parse(URL);
static final String id = "id";
static final String name = "name";
static final int uriCode = 1;
private static HashMap<String, String> values;
// Used to match uris with Content Providers
static final UriMatcher uriMatcher;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(PROVIDER_NAME, "cpcontacts", uriCode);
}
private SQLiteDatabase sqlDB;
static final String DATABASE_NAME = "myContacts";
static final String TABLE_NAME = "names";
static final int DATABASE_VERSION = 1;
static final String CREATE_DB_TABLE = " CREATE TABLE " + TABLE_NAME
+ " (id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ " name TEXT NOT NULL);";
@Override
public boolean onCreate() {
DatabaseHelper dbHelper = new DatabaseHelper(getContext());
sqlDB = dbHelper.getWritableDatabase();
if (sqlDB != null) {
return true;
}
return false;
}
// Returns a cursor that provides read and write access to the results of the query
// Uri : Links to the table in the provider (The From part of a query)
// projection : an array of columns to retrieve with each row
// selection : The where part of the query selection
// selectionArgs : The argument part of the where (where id = 1)
// sortOrder : The order by part of the query
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
// Used to create a SQL query
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
// Set table to query
queryBuilder.setTables(TABLE_NAME);
// Used to match uris with Content Providers
switch (uriMatcher.match(uri)) {
case uriCode:
// A projection map maps from passed column names to database column names
queryBuilder.setProjectionMap(values);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
// Cursor provides read and write access to the database
Cursor cursor = queryBuilder.query(sqlDB, projection, selection, selectionArgs, null,
null, sortOrder);
// Register to watch for URI changes
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
// Handles requests for the MIME type (Type of Data) of the data at the URI
@Override
public String getType(Uri uri) {
// Used to match uris with Content Providers
switch (uriMatcher.match(uri)) {
// vnd.android.cursor.dir/cpcontacts states that we expect multiple pieces of data
case uriCode:
return "vnd.android.cursor.dir/cpcontacts";
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
}
// Used to insert a new row into the provider
// Receives the URI (Uniform Resource Identifier) for the Content Provider and a set of values
@Override
public Uri insert(Uri uri, ContentValues values) {
// Gets the row id after inserting a map with the keys representing the the column
// names and their values. The second attribute is used when you try to insert
// an empty row
long rowID = sqlDB.insert(TABLE_NAME, null, values);
// Verify a row has been added
if (rowID > 0) {
// Append the given id to the path and return a Builder used to manipulate URI
// references
Uri _uri = ContentUris.withAppendedId(CONTENT_URL, rowID);
// getContentResolver provides access to the content model
// notifyChange notifies all observers that a row was updated
getContext().getContentResolver().notifyChange(_uri, null);
// Return the Builder used to manipulate the URI
return _uri;
}
Toast.makeText(getContext(), "Row Insert Failed", Toast.LENGTH_LONG).show();
return null;
}
// Deletes a row or a selection of rows
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int rowsDeleted = 0;
// Used to match uris with Content Providers
switch (uriMatcher.match(uri)) {
case uriCode:
rowsDeleted = sqlDB.delete(TABLE_NAME, selection, selectionArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
// getContentResolver provides access to the content model
// notifyChange notifies all observers that a row was updated
getContext().getContentResolver().notifyChange(uri, null);
return rowsDeleted;
}
// Used to update a row or a selection of rows
// Returns to number of rows updated
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
int rowsUpdated = 0;
// Used to match uris with Content Providers
switch (uriMatcher.match(uri)) {
case uriCode:
// Update the row or rows of data
rowsUpdated = sqlDB.update(TABLE_NAME, values, selection, selectionArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
// getContentResolver provides access to the content model
// notifyChange notifies all observers that a row was updated
getContext().getContentResolver().notifyChange(uri, null);
return rowsUpdated;
}
// Creates and manages our database
private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase sqlDB) {
sqlDB.execSQL(CREATE_DB_TABLE);
}
// Recreates the table when the database needs to be upgraded
@Override
public void onUpgrade(SQLiteDatabase sqlDB, int oldVersion, int newVersion) {
sqlDB.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
onCreate(sqlDB);
}
}
}
MainActivity.java
package com.newthinktank.derekbanas.contactprovider;
import android.app.Activity;
import android.content.ContentValues;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
EditText contactNameEditText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
contactNameEditText = (EditText) findViewById(R.id.contactNameEditText);
}
public void addName(View view) {
// Get the name supplied
String name = contactNameEditText.getText().toString();
// Stores a key value pair
ContentValues values = new ContentValues();
values.put(ContactProvider.name, name);
// Provides access to other applications Content Providers
Uri uri = getContentResolver().insert(ContactProvider.CONTENT_URL, values);
Toast.makeText(getBaseContext(), "New Contact Added", Toast.LENGTH_LONG)
.show();
}
}
activity_main.xml
<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" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/contactNameEditText"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:hint="Add Name" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/addContactButton"
android:text="Add Name"
android:onClick="addName"
android:layout_below="@+id/contactNameEditText"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
</RelativeLayout>
Get Contacts Code
MainActivity.java
package com.newthinktank.derekbanas.getcontacts;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.content.CursorLoader;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
// The URL used to target the content provider
static final Uri CONTENT_URL =
Uri.parse("content://com.newthinktank.derekbanas.contactprovider.ContactProvider/cpcontacts");
TextView contactsTextView = null;
EditText deleteIDEditText, idLookupEditText, addNameEditText;
CursorLoader cursorLoader;
// Provides access to other applications Content Providers
ContentResolver resolver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
resolver = getContentResolver();
contactsTextView = (TextView) findViewById(R.id.contactsTextView);
deleteIDEditText = (EditText) findViewById(R.id.deleteIDEditText);
idLookupEditText = (EditText) findViewById(R.id.idLookupEditText);
addNameEditText = (EditText) findViewById(R.id.addNameEditText);
getContacts();
}
public void getContacts(){
// Projection contains the columns we want
String[] projection = new String[]{"id", "name"};
// Pass the URL, projection and I'll cover the other options below
Cursor cursor = resolver.query(CONTENT_URL, projection, null, null, null);
String contactList = "";
// Cycle through and display every row of data
if(cursor.moveToFirst()){
do{
String id = cursor.getString(cursor.getColumnIndex("id"));
String name = cursor.getString(cursor.getColumnIndex("name"));
contactList = contactList + id + " : " + name + "\n";
}while (cursor.moveToNext());
}
contactsTextView.setText(contactList);
}
public void deleteContact(View view) {
String idToDelete = deleteIDEditText.getText().toString();
// Use the resolver to delete ids by passing the content provider url
// what you are targeting with the where and the string that replaces
// the ? in the where clause
long idDeleted = resolver.delete(CONTENT_URL,
"id = ? ", new String[]{idToDelete});
getContacts();
}
public void lookupContact(View view) {
// The id we want to search for
String idToFind = idLookupEditText.getText().toString();
// Holds the column data we want to retrieve
String[] projection = new String[]{"id", "name"};
// Pass the URL for Content Provider, the projection,
// the where clause followed by the matches in an array for the ?
// null is for sort order
Cursor cursor = resolver.query(CONTENT_URL,
projection, "id = ? ", new String[]{idToFind}, null);
String contact = "";
// Cycle through our one result or print error
if(cursor.moveToFirst()){
String id = cursor.getString(cursor.getColumnIndex("id"));
String name = cursor.getString(cursor.getColumnIndex("name"));
contact = contact + id + " : " + name + "\n";
} else {
Toast.makeText(this, "Contact Not Found", Toast.LENGTH_SHORT).show();
}
contactsTextView.setText(contact);
}
public void showContacts(View view) {
getContacts();
}
public void addContact(View view) {
// Get the name to add
String nameToAdd = addNameEditText.getText().toString();
// Put in the column name and the value
ContentValues values = new ContentValues();
values.put("name", nameToAdd);
// Insert the value into the Content Provider
resolver.insert(CONTENT_URL, values);
getContacts();
}
}
activity_main.xml
<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" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Show Contacts"
android:id="@+id/btnRetrieve"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:onClick="showContacts"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Contacts"
android:id="@+id/contactsTextView"
android:ems="10"
android:layout_centerVertical="true"
android:layout_alignRight="@+id/findContactButton"
android:layout_alignEnd="@+id/findContactButton" />
<EditText
android:layout_width="150dp"
android:layout_height="wrap_content"
android:inputType="number"
android:ems="10"
android:id="@+id/deleteIDEditText"
android:layout_below="@+id/btnRetrieve"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:hint="ID to Delete"
android:layout_marginTop="10dp"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Delete ID"
android:id="@+id/deleteIDButton"
android:layout_below="@+id/btnRetrieve"
android:layout_toRightOf="@+id/deleteIDEditText"
android:layout_toEndOf="@+id/deleteIDEditText"
android:layout_marginLeft="30dp"
android:layout_marginStart="30dp"
android:onClick="deleteContact"/>
<EditText
android:layout_width="150dp"
android:layout_height="wrap_content"
android:inputType="number"
android:ems="10"
android:id="@+id/idLookupEditText"
android:layout_below="@+id/deleteIDEditText"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:hint="ID to Find"
android:layout_marginTop="10dp"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Find Contact"
android:id="@+id/findContactButton"
android:layout_below="@+id/deleteIDButton"
android:layout_toRightOf="@+id/idLookupEditText"
android:layout_toEndOf="@+id/idLookupEditText"
android:layout_marginLeft="30dp"
android:layout_marginStart="30dp"
android:onClick="lookupContact"/>
<EditText
android:layout_width="150dp"
android:layout_height="wrap_content"
android:inputType="textPersonName"
android:ems="10"
android:id="@+id/addNameEditText"
android:layout_below="@+id/idLookupEditText"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:hint="Name to Add"
android:layout_marginTop="10dp"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Add Contact"
android:id="@+id/addContactButton"
android:layout_below="@+id/findContactButton"
android:layout_alignTop="@+id/addNameEditText"
android:layout_toRightOf="@+id/addNameEditText"
android:layout_toEndOf="@+id/addNameEditText"
android:layout_marginLeft="30dp"
android:layout_marginStart="30dp"
android:onClick="addContact"/>
</RelativeLayout>
Are you still considering a Unity series ?
Yes I’ll start with Open GL and libgdx first
Dude ur a very great guy.. Please make live wallpaper for android please teach us.. Others are asking money for softwares please help! God bless u
Thank you 🙂 I’ll make a wallpaper very soon. May God bless you as well.
I get the libGDX but why not Unity and what IDE would you use?
Actually I’ll first show how to create a framework for games so that they are completely understandable. I’ll then work my way up through the other frameworks.